2013年6月16日 星期日

2013/06/16

今天去練習超多人的, 看著年輕一輩,突然覺得自己有點格格不入 ~_~

 (好像該從Tricking退出了嗎)

Anyway, 每個禮拜天晚上的讀書會又開始了!

準備迎接接下來的挑戰!



2013年6月11日 星期二

[C#] WebApi 補充 : 設定媒體類型

MVC4第一支Web Api 這篇文章有提到在 Global.asax 加入以下程式碼,
(或是加到「App_Start」→「WebApiConfig.cs」的Register函式)
可以由送出Http GET請求Url的參數決定預設回傳訊息的媒體類型:

//設定一個URL的新參數
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("json", "true", "application/json"));
//設定一個URL的新參數
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "text/xml"));

Example,
http://localhost:33855/api/Book?xml=true


另外也可以在「App_Start」→「WebApiConfig.cs」的Register函式 加入以下程式碼,手動移除JSONXML格式化程式,限制Web Api只回應特定的媒體類型。

//移除回傳Json格式
config.Formatters.Remove(config.Formatters.JsonFormatter);
//移除回傳XML格式

config.Formatters.Remove(config.Formatters.XmlFormatter);

2013年6月7日 星期五

[C#] 使用HttpClient取得WebApi服務

使用HttpClient取得WebApi服務

JB

延續我們已經建立好的Book Web Api, 除了利用前端語法( 文章:使用jQuery取得WebApi服務 ) 去使用WebApiCRUD方法。 我們也也可以使用新的HttpClient 使用Web Api

※備註:
HttpClient
VS2012 內建於System.Net.Http (v4.0.0.0) 中,但是如果要使用文章中的PutAsJsonAsyncPostAsJsonAsync等方法,必須加入HttpClientExtensions 這個參考,最快的方式是直接使用Nuget下載「
MicrosoftASP.NET Web API Client Libraries」這個套件


1.           如果尚未建立Web Api,請參考以下表格,建立一個~

    

2.           加入Windows Form/ WPF /Console程式專案都可以,名稱:ApiClient

3.           新增以下Class ..



4.           Book.cs

public class Book
{
 
public string ID { get; set; }
 
public string NAME { get; set; }
 
public Nullable<decimal> PRICE { get; set; }
}

5.           AppSetting.cs
在此類別建立HttpClient並設定它的基底位址等資訊。

public  class ApiSetting : IDisposable
{
  public static String API_URL = "http://localhost:33855/";
  public static String ROUTE_URI = "api/Book/";

  /// <summary>
  /// Create a HttpClient
  /// </summary>
  /// <returns></returns>
  public  HttpClient CreateHttpClient()
  {
     
//Intial HttpClient
     
HttpClient API_CLIENT = new HttpClient();
     
//Set the http service uri
     API_CLIENT.BaseAddress =
new Uri(ApiSetting.API_URL);
     
//The http service is based on JSON format
     API_CLIENT.DefaultRequestHeaders.Accept.Add(
           
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
     
return API_CLIENT;
  }
}

6.           請記得在使用Web Api服務前,先利用上面的ApiSetting建立一個HttpClient
Get
PostPutDelect都是一樣,所以只列出一次在Get.cs 中 Initial HttpClient的程式碼。

public class Get
{
 
private HttpClient API_CLIENT = null;
 
public Get()
  {
    
using(ApiSetting _apiSetting = new ApiSetting())
   {
     API_CLIENT = _apiSetting.CreateHttpClient();
   }
  }
    // …
}


7.           接下來是真正HttpClientWeb APi操控資料的部分~~

GET (
取得所有資料)


public void GetWebApi()
{
 
String msg;
  //
使用非同步方法
  HttpResponseMessage resp = API_CLIENT.GetAsync(ApiSetting.ROUTE_URI).Result;
  if (resp.IsSuccessStatusCode)
  {
    
var books = resp.Content.ReadAsAsync<IEnumerable<Book>>().Result;
    
foreach (var book in books)
    {
      msg =
String.Format("代號 {0},書名 {1},價格 {2} \n", book.ID, book.NAME, book.PRICE.ToString());
    }
  }
  else
  {
    msg =
String.Format("{0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase));
  }
  Console.WriteLine(msg);
}

GET (
取得單筆資料)


public void GetWebApi_ById(String id)
{

  String msg;

  //
組出GET Uri : api/Book/{id}
  String getRouteUri = ApiSetting.ROUTE_URI + id;
  //使用非同步方法
  HttpResponseMessage resp = API_CLIENT.GetAsync(getRouteUri).Result;
  if (resp.IsSuccessStatusCode)
  {
    var book = resp.Content.ReadAsAsync<Book>().Result;
    msg = (book ==
null) ? "查無資料!"
       :
String.Format("代號 {0},書名 {1},價格 {2} \n", book.ID, book.NAME, book.PRICE.ToString());
  }
  else
  {
    msg =
String.Format("{0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
  Console.WriteLine(msg);
}

POST (
建立單筆資料)


public void PostWebApi(Book book)
{
  String msg = "";
 
//方法一: 使用 PostAsJsonAsync
 
var resp = API_CLIENT.PostAsJsonAsync(ApiSetting.ROUTE_URI, book).Result;
 
///方法二: 使用 PostAsync
 
/*
 
// Create the JSON formatter.
 
MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
 
// Use the JSON formatter to create the content of the request body.
 
HttpContent content = new ObjectContent<Book>(book, jsonFormatter);
 
// Send the request.
 
HttpResponseMessage resp = API_CLIENT.PostAsync("api/book", content).Result;
 
*/
 
if (resp.IsSuccessStatusCode){
     msg =
String.Format("新增成功 : {0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
 
else{
     msg =
String.Format("新增失敗 : {0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
  Console.WriteLine(msg);
}

DELET (
刪除單筆資料)


public void DeleteWebApi(String id)
{
  String msg = "";
  //組出DELETE Uri  : api/Book/{id}
  String delRouteUrl = ApiSetting.ROUTE_URI + id;
  ///使用 DeleteAsync
  var resp = API_CLIENT.DeleteAsync(delRouteUrl).Result;
  if (resp.IsSuccessStatusCode){
    msg =
String.Format("刪除成功 : {0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
  else{
    msg =
String.Format("刪除失敗 : {0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
  Console.WriteLine(msg);
}

PUT (
更新單筆資料)


public void PutWebApi(Book book)
{
 
String msg = "";
 
///組出PUT Uri  : api/Book/{id}
 
String putRouteUri = ApiSetting.ROUTE_URI + book.ID;
 
///使用 PutAsJsonAsync
 
var resp = API_CLIENT.PutAsJsonAsync(putRouteUri, book).Result;
 
 
if (resp.IsSuccessStatusCode){
     msg =
String.Format("更新成功 : {0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
 
else{
     msg =
String.Format("更新失敗 : {0} {1}", (int?)resp.StatusCode, resp.ReasonPhrase);
  }
  Console.WriteLine(msg);       
}


8.           至於其他實作的部分就請讀者自行設計了,以下列出幾張HttpClient使用Web Api的結果。






9.           Reference
Calling a Web API From a .NET Client (C#)

10.       結束












2013年6月6日 星期四

[C#] 使用jQuery取得WebApi服務

使用jQuery取得WebApi服務

延續我們已經建立好的Book Web Api, 除了利用HttpClient ( 文章:使用HttpClient取得WebApi服務去使用WebApiCRUD方法。 我們也也可以選擇在前端網頁直接用jQuery使用Web Api。 

1.           如果尚未建立Web Api,請參考以下表格,建立一個~


2.           加入一個MVC4 Web應用程式專案,名稱:Mvc.Thru.WebApi

3.           加入一個空白的 Controller BookController


加入後,目前的BookController只有一個Index方法。 我們預計要在這個範例放入一下以下內容:

Page
功能
對應的CRUD方法
Index
列出所有書籍,
查詢某一本書籍
GET
Create
建立一本書籍資料
POST
Edit
1.       編輯某本書籍(更新或刪除)
2.       IndexURL參數過來。
PUT, DELETE

所以我們在BookController中再加入以下程式碼:

public class BooksController : Controller
{
 
public ActionResult Index()
  {
    
return View();
  }
 
public ActionResult Create()
  {
     
return View();
   }
  
public ActionResult Edit(String id)
   {
     
return View();
   }
}

4.         加入Controller的方法後,接著建立View
當然本例是沒有任何Model的唷。



加入後的方案總管


5.         接下來開始寫ViewHtml部份,注意每個View都有內嵌一個CallWebApi-XXX.js檔,是放我們等下要實作的jQuery部分,目前請先建立空檔即可。

Index


@{
ViewBag.Title =
"Book Index";
}

@section scripts
{
  ///新增按鈕事件
 
function RedirectCreatePage() {
        location.href =
"/Book/Create"; //導向至Create頁面
  }
 
<script src="~/Scripts/CallWebApi-Get.js"></script>
}

<!--功能-->
<div>
<form>
<label for="bookId" >ID查詢 : </label>
  <input type="text" id="tb_bookId" maxlength="3" />
 
<input type="button" id="bt_search" value="Search"/>
</form>
</div>
<!--第二個div放單筆查詢Book的資料-->
<div>
<p id="book"></p>
</div>
<!--第三個div放所有查詢Book的資料-->
<div>
<table id="BookList" >
<tr>
 
<td>代號</td><td></td>
 
<td>書籍名稱</td><td></td>
 
<td>價錢</td>
</tr>
</table>
</div>
<!--第四個div放新增按鈕-->
<div>
<input type="button" id="bt_create" value="新增" onclick="RedirectCreatePage();"/>
</
div>

Create


@{
ViewBag.Title =
"Create";
Layout =
"~/Views/Shared/_Layout.cshtml";
}

@section scripts
{
 
<script src="~/Scripts/CallWebApi-Create.js"></script>
}
<
h2>新增資料</h2>
<
label for="ID">代號</label>
<
input type="text"  id="tb_id" value="" />
<
label for="NAME">書籍名稱</label>
<
input type="text" id="tb_name"  value=""/>
<
label for="PRICE">價錢</label>
<
input type="text" id="tb_price" value="0"/>
<
br />
<
input type="button" id="bt_create"  value="新增"/>

Edit


@{
ViewBag.Title =
"Edit";
Layout =
"~/Views/Shared/_Layout.cshtml";
}

@section scripts
{
<script src="~/Scripts/CallWebApi-Put.js"></script>
<script src="~/Scripts/CallWebApi-Delete.js"></script>
}

<h2>編輯資料</h2>
<label for="ID">代號</label>
<input type="text" readonly="true" id="tb_id" value="@ViewBag.ID" />
<label for="NAME">書籍名稱</label>
<input type="text" id="tb_name"  value="@ViewBag.NAME"/>
<label for="PRICE">價錢</label>
<input type="text" id="tb_price" value="@ViewBag.PRICE"/>
<br />
<input type="button" id="bt_update"  value="更新"/>
<input type="button" id="bt_delete"  value="刪除"/>


因為Edit頁面上的資料會從IndexURL參數過來,所以我們放了幾個ViewBag在上面,將顯示IDTextBox設成唯獨,並在Controller中稍加一些程式碼:

public ActionResult Edit(String id)
{
 
//設定帶過來的值到頁面上
  ViewBag.ID = id;
  ViewBag.NAME = Request[
"NAME"].ToString();
  ViewBag.PRICE = Request[
"PRICE"].ToString();
 
return View();
}

6.     以上HTML和後端都準備好之後,目前頁面可正常瀏覽,但是沒辦法操作資料,我們接下來便要開始撰寫jQuery 來使用Web Api 如果剛才還沒有新增前面四支空的 js檔,請如下新增在Script資料夾。


7.          jQuery 使用Web Api GET方法:CallWebApi-Create.js  (載入於Index.cshtml)

$(function () {
  //Web api url
  var API_URL = "http://localhost:33855/api/Book/";

  //利用Get方式取得。
  $.getJSON( API_URL,
  function (data) {
        $.each(data,
function (key, val) {
       
//格式化文字資料,以方便顯示
       
// var str = val.NAME + ' : $' + val.PRICE;
       
//Book資料設定成 li 項目,再加入 ul 元素中
       
//$('<li/>', { html: str }).appendTo($('#books'));
       
var content = "";
        content +=
"<tr>";
        content +=
"<td>" + val.ID + "<td/>";
        content +=
"<td>" + val.NAME + "<td/>";
        content +=
"<td>"+val.PRICE+"<td/>";
        content +=
"<tr/>";
        $(
'#BookList').append(content);
  });
  }).fail(
    function (jqXHR, textStatus, err) {
      alert(
"Error : " + err.toString());
});

$(
'#bt_search').bind("click",
  
function () {
       
var id = $('#tb_bookId').val();
        $.getJSON( API_URL + id,
       
function (data) {
           
var str = data.NAME + ' : $' + data.PRICE;
           
var linkStr = "<a href='/Book/Edit/" + data.ID + "?NAME=" + data.NAME + "&PRICE="+data.PRICE+"'>" + str + "</a>";
            $(
'#book').append(linkStr);
           
//$('#book').html(str);
        }).fail(
       
function (jqXHR, textStatus, err) {
           $(
'#book').html('Error : ' + err);
        });
   });
});
※     第一段是使用$.getJSON 方法去使用Web APiGET,取得資料後,再把每一筆資料放入Index View 裡面的<Table>中。
※     第二段是實作查詢單筆的Click事件,依舊是使用Web APiGET,只不過我們在api Url最後加上單筆書籍的ID,讓Web Api回傳單筆資料。 再將此筆資料以超連結<a href=..></a>的格式放入頁面, 讓使用者點選此筆連結後,可直接到Edit頁面。
(超連結到Edit的網址範例:http://localhost/Book/Edit/001?NAME=BOOK01&PRICE=1000)
完成後的結果如下圖:




8.      jQuery 使用Web Api PUT方法:CallWebApi-Put.js (載入於Edit.cshtml)
還記得我們在Edit頁面的資料是從Index帶過來的,所以上面的步驟完成後,我們目前可以看到Edit頁面上的資料已經自動帶入了,我們只要再實作【更新】的Click事件裡面使用Web ApiPUT方法。



$(function () {
//Web api url
var API_URL = "http://localhost:33855/api/Book/";

$(
'#bt_update').bind("click",
  
function () {
       
//取得BookID
       
var id = $('#tb_id').val();
       
//要給WebApiJSON字串
       
var uptJson = JSON.stringify(
              { ID: id, NAME: $(
'#tb_name').val(), PRICE: parseInt($('#tb_price').val()) });
       
//ajax呼叫WebApiPUT方法
        $.ajax({
            url: API_URL + id,
            cache:
false,
            type:
"PUT",
            contentType:
"application/json; charset=utf-8",
            data: uptJson,
            success:
function () { location.href = "/Book/"; }
        })
.fail(
            
function(jqXHR, textStatus, err){
               alert(
"更新失敗:"+err);
          });
});
});

※     這邊我們必須指定要使用的Http方法,以及送過去的ContentTypedataJSON)。
※     更新成功後,會直接回到Index頁面。

9.          jQuery 使用Web Api DELETE方法:CallWebApi-Delete.js (載入於Edit.cshtml)
Edit
頁面上,還有一個刪除功能,我們一併完成它


$(function () {
//Web api url
var API_URL = "http://localhost:33855/api/Book/";

$(
'#bt_delete').bind("click",
 
function () {
       
//取得BookID
       
var id = $('#tb_id').val();
       
//ajax呼叫WebApiDelete方法
        $.ajax({
            url: API_URL + id,
            cache:
false,
            type:
"DELETE",
            success:
function () { location.href = "/Book/"; }
         }).fail(
           
function (jqXHR, textStatus, err) {
               alert(
"刪除失敗:" + err);
          })
});
});

※     因為Delete方法只要知道ID,所以就省略了設定data的部分。

10.      jQuery 使用Web Api POST方法:CallWebApi-Post.js  (載入於Create.cshtml)

$(function () {
//Web api url
var API_URL = "http://localhost:33855/api/Book/";
$(
'#bt_create').bind("click",
       
function () {
       
//取得BookID
       
var id = $('#tb_id').val();
       
//要給WebApiJSON字串
       
var uptJson = JSON.stringify(
           { ID: id, NAME: $(
'#tb_name').val(), PRICE: parseInt($('#tb_price').val()) });
       
//ajax呼叫WebApiPUT方法
        $.ajax({
            url: API_URL,
            cache:
false,
            type:
"POST",
            contentType:
"application/json; charset=utf-8",
            data: uptJson,
            success:
function () { location.href = "/Book/"; }
        }).fail(
            
function(jqXHR, textStatus, err){
                 alert(
"新增失敗:"+err);
         });
 });
});

11.      以上jQuery的部分終於大功造成,如果View有正常嵌入這些jQuery的話,現在應該可以做查詢/新增/修改/刪除。 最後,別忘了在測試之前,請確定Web Api的服務有起來唷!










13.      結束