Web API 入門指南

Web API是一個比較寬泛的概念。這裏我們提到Web API特指ASP.NET Web API。

這篇文章中我們主要介紹Web API的主要功能以及與其他同類型框架的對比,最後通過一些相對複雜的實例展示如何通過Web API構建http服務,同時也展示了Visual Studio構建.net項目的各種強大。

目錄

什麼是 Web API

官方定義如下,強調兩個關鍵點,即可以對接各種客戶端(瀏覽器,移動設備),構建http服務的框架。

ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework.

Web API在ASP.NET完整框架中地位如下圖,與SignalR一起同爲構建Service的框架。Web API負責構建http常規服務,而SingalR主要負責的是構建實時服務,例如股票,聊天室,在線遊戲等實時性要求比較高的服務。

Picture20

 

爲什麼要用 Web API

Web API最重要的是可以構建面向各種客戶端的服務。另外與WCF REST Service不同在於,Web API利用Http協議的各個方面來表達服務(例如 URI/request response header/caching/versioning/content format),因此就省掉很多配置。

Picture2

 

當你遇到以下這些情況的時候,就可以考慮使用Web API了。

  • 需要Web Service但是不需要SOAP
  • 需要在已有的WCF服務基礎上建立non-soap-based http服務
  • 只想發佈一些簡單的Http服務,不想使用相對複雜的WCF配置
  • 發佈的服務可能會被帶寬受限的設備訪問
  • 希望使用開源框架,關鍵時候可以自己調試或者自定義一下框架

功能簡介

Web API的主要功能

1. 支持基於Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, update, delete)操作

    通過不同的http動作表達不同的含義,這樣就不需要暴露多個API來支持這些基本操作。

2. 請求的回覆通過Http Status Code表達不同含義,並且客戶端可以通過Accept header來與服務器協商格式,例如你希望服務器返回JSON格式還是XML格式。

3. 請求的回覆格式支持 JSON,XML,並且可以擴展添加其他格式。

4. 原生支持OData

5. 支持Self-host或者IIS host。

6. 支持大多數MVC功能,例如Routing/Controller/Action Result/Filter/Model Builder/IOC Container/Dependency Injection。

Web API vs MVC

你可能會覺得Web API 與MVC很類似,他們有哪些不同之處呢?先上圖,這就是他們最大的不同之處。

Picture1

詳細點說他們的區別,

  • MVC主要用來構建網站,既關心數據也關心頁面展示,而Web API只關注數據
  • Web API支持格式協商,客戶端可以通過Accept header通知服務器期望的格式
  • Web API支持Self Host,MVC目前不支持
  • Web API通過不同的http verb表達不同的動作(CRUD),MVC則通過Action名字表達動作
  • Web API內建於ASP.NET System.Web.Http命名空間下,MVC位於System.Web.Mvc命名空間下,因此model binding/filter/routing等功能有所不同
  • 最後,Web API非常適合構建移動客戶端服務

Web API vs WCF

發佈服務在Web API和WCF之間該如何取捨呢?這裏提供些簡單地判斷規則,

  • 如果服務需要支持One Way Messaging/Message Queue/Duplex Communication,選擇WCF
  • 如果服務需要在TCP/Named Pipes/UDP (wcf 4.5),選擇WCF
  • 如果服務需要在http協議上,並且希望利用http協議的各種功能,選擇Web API
  • 如果服務需要被各種客戶端(特別是移動客戶端)調用,選擇Web API

Web API 實戰 (Web API + MongoDB + knockoutjs)

ASP.NET網站上有很多簡單的Web API實例,看看貼圖和實例代碼你就明白怎麼用了。這裏我們通過一個稍微複雜一點的實例來展示下Web API的功能。

涉及技術

在我們的實例裏面用到了:

服務URI Pattern

ActionHttp verbURI
Get contact listGET/api/contacts
Get filtered contactsGET/api/contacts?$top=2
Get contact by IDGET/api/contacts/id
Create new contactPOST/api/contacts
Update a contactPUT/api/contacts/id
Delete a contactDELETE/api/contacts/id

準備工作

1. 下載並安裝Mongo DB,步驟看這裏

2. Mongo DB C# driver下載可以在nuget搜索mongocsharpdriver。

3. 如果想本地察看數據庫中內容,下載MongoVUE

4. Knockoutjs下載可以在nuget搜索knockoutjs。

代碼實現

1. 創建項目

創建MVC4 Web Application

1

在Project Template中選擇Web API

2

然後項目就創建成了,Controllers裏面有一個ValuesController,是自動生成的一個最簡單的Web API Controller。

正如我們前面所說,裏面引用的是System.Web.Http命名空間。

3

2. 創建model

在model裏面添加Contact類

4

代碼如下,其中BsonId需要mongocsharpdriver。

1
2
3
4
5
6
7
8
9
public class Contact
    {
        [BsonId]
        public string Id { get; set; }
        public string Name { get; set; }
        public string Phone { get; set; }
        public string Email { get; set; }
        public DateTime LastModified { get; set; }
    }

我們需要添加mongosharpdriver。

7

8

另外我們需要在Model中添加Repository,Controller通過該類來訪問Mongo DB。

1
2
3
4
5
6
7
public interface IContactRepository {
        IEnumerable GetAllContacts();
        Contact GetContact(string id);
        Contact AddContact(Contact item);
        bool RemoveContact(string id);
        bool UpdateContact(string id, Contact item);  
    }

ContactRepository的完整實現如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class ContactRepository : IContactRepository
    {
        MongoServer _server = null;
        MongoDatabase _database = null;
        MongoCollection _contacts = null;
 
        public ContactRepository(string connection)
        {
            if (string.IsNullOrWhiteSpace(connection))
            {
                connection = "mongodb://localhost:27017";
            }
 
            _server = new MongoClient(connection).GetServer();
            _database = _server.GetDatabase("Contacts");
            _contacts = _database.GetCollection("contacts");
 
            // Reset database and add some default entries
            _contacts.RemoveAll();
            for (int index = 1; index < 5; index++)
            {
                Contact contact1 = new Contact
                {
                    Email = string.Format("test{0}@example.com", index),
                    Name = string.Format("test{0}", index),
                    Phone = string.Format("{0}{0}{0} {0}{0}{0} {0}{0}{0}{0}", index)
                };
                AddContact(contact1);
            }
        }
 
        public IEnumerable GetAllContacts()
        {
            return _contacts.FindAll();
        }
 
        public Contact GetContact(string id)
        {
            IMongoQuery query = Query.EQ("_id", id);
            return _contacts.Find(query).FirstOrDefault();
        }
 
        public Contact AddContact(Contact item)
        {
            item.Id = ObjectId.GenerateNewId().ToString();
            item.LastModified = DateTime.UtcNow;
            _contacts.Insert(item);
            return item;
        }
 
        public bool RemoveContact(string id)
        {
            IMongoQuery query = Query.EQ("_id", id);
            WriteConcernResult result = _contacts.Remove(query);
            return result.DocumentsAffected == 1;
        }
 
        public bool UpdateContact(string id, Contact item)
        {
            IMongoQuery query = Query.EQ("_id", id);
            item.LastModified = DateTime.UtcNow;
            IMongoUpdate update = Update
                .Set("Email", item.Email)
                .Set("LastModified", DateTime.UtcNow)
                .Set("Name", item.Name)
                .Set("Phone", item.Phone);
            WriteConcernResult result = _contacts.Update(query, update);
            return result.UpdatedExisting;
        }
    }

3. 添加Controller

右鍵Controllers目錄選擇添加Controller

5

選擇Empty API controller,將Controller命名爲ContactsController

6

添加如下代碼,可以看到Controller中的API方法名就是以http verb命名的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class ContactsController : ApiController
    {
        private static readonly IContactRepository _contacts = new ContactRepository(string.Empty);
 
        public IQueryable Get()
        {
            return _contacts.GetAllContacts().AsQueryable();
        }
 
        public Contact Get(string id)
        {
            Contact contact = _contacts.GetContact(id);
            if (contact == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
 
            return contact;
        }
 
        public Contact Post(Contact value)
        {
            Contact contact = _contacts.AddContact(value);
            return contact;
        }
 
        public void Put(string id, Contact value)
        {
            if (!_contacts.UpdateContact(id, value))
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }
 
        public void Delete(string id)
        {
            if (!_contacts.RemoveContact(id))
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }
    }

4. 添加View

首先添加Knockoutjs庫,

9

Knockoutjs通過MVVM模式來實現動態html綁定數據,如下圖,其中View-Model是客戶端的javascript object保存的model數據。

webapi_ef16

先打開HomeController,裏面添加一個新的Action代碼如下,因爲我們要在MVC中對於ContactsController添加對應的View。

1
2
3
4
5
6
7
public ActionResult Admin()
        {
            string apiUri = Url.HttpRouteUrl("DefaultApi", new { controller = "contacts", });
            ViewBag.ApiUrl = new Uri(Request.Url, apiUri).AbsoluteUri.ToString();
 
            return View();
        }

然後右鍵Admin方法,選擇添加View

10

選擇Create strongly-typed view,在model class中選擇Contact類。

11

添加View的完整代碼,注意view中我們通過js去訪問WebAPI,以及通過動態綁定將數據呈現在網頁上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@model WebAPIDemo.Models.Contact
 
@{
    ViewBag.Title = "Admin";
}
 
@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.3.0.js")"></script>
  <script type="text/javascript">
      function ProductsViewModel() {
          var self = this;
          self.products = ko.observableArray();
 
          var baseUri = '@ViewBag.ApiUrl';
 
          self.create = function (formElement) {
              // If valid, post the serialized form data to the web api
              $(formElement).validate();
              if ($(formElement).valid()) {
                  $.post(baseUri, $(formElement).serialize(), null, "json")
                      .done(function (o) { self.products.push(o); });
              }
          }
 
          self.update = function (product) {
              $.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
          }
 
          self.remove = function (product) {
              // First remove from the server, then from the UI
              $.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
                  .done(function () { self.products.remove(product); });
          }
 
          $.getJSON(baseUri, self.products);
      }
 
      $(document).ready(function () {
          ko.applyBindings(new ProductsViewModel());
      })
  </script>
}
 
<h2>Admin</h2>
<div class="content">
    <div class="float-left">
    <ul id="update-products" data-bind="foreach: products">
 
        <li>
            <div>
                <div class="item">ID</div> <span data-bind="text: $data.Id"></span>
            </div>
            <div>
                <div class="item">Name</div>
                <input type="text" data-bind="value: $data.Name"/>
            </div>
            <div>
                <div class="item">Phone</div>
                <input type="text" data-bind="value: $data.Phone"/>
            </div>
            <div>
                <div class="item">Email</div>
                <input type="text" data-bind="value: $data.Email"/>
            </div>
            <div>
                <div class="item">Last Modified</div> <span data-bind="text: $data.LastModified"></span>
            </div>
            <div>
                <input type="button" value="Update" data-bind="click: $root.update"/>
                <input type="button" value="Delete Item" data-bind="click: $root.remove"/>
            </div>
        </li>
    </ul>
    </div>
 
    <div class="float-right">
    <h2>Add New Product</h2>
    <form id="addProduct" data-bind="submit: create">
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>Contact</legend>
            @Html.EditorForModel()
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
    </form>
    </div>
</div>

接下來在_layout.cshtml中添加一個admin頁面的鏈接如下

1
2
3
4
<ul id="menu">
    <li>@Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)</li>
    <li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li>
    <li>@Html.ActionLink("Admin", "Admin", "Home")</li>
 
</ul>

5. 測試與調試

大功告成,直接運行下我們的作品,我們的admin鏈接也顯示在右上角,

12

Admin頁面的樣子,Contact list是動態加載進來的,可以通過這個頁面做添加,修改,刪除的操作。

13

通過IE network capture來查看請求內容,

重新加載頁面,可以看到回覆的格式爲JSON,

14

JSON內容就是我們mock的一些數據。

image

接下來我們修改,刪除,又添加了一條記錄,可以看到使用了不同的http method。

image

通過前面安裝的mongovue來查看下DB種的數據,先添加的user也在其中,令我感到欣慰。。。

image


原文鏈接:https://www.cnblogs.com/guyun/p/4589115.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章