Web API 入门指南

Web API是一个比较宽泛的概念。这里我们提到Web API特指ASP.NET Web API。

这篇文章中我们主要介绍Web API的主要功能以及与其他同类型框架的对比,最后通过一些相对复杂的实例展示如何通过Web API构建http服务,同时也展示了Visual Studio构建.net项目的各种强大。

目录

什么是 Web API
为什么要用 Web API
功能简介
Web API vs MVC
Web API vs WCF
Web API 实战 (Web API + MongoDB + knockoutjs)
涉及技术
服务URI Pattern
准备工作
代码实现

什么是 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主要负责的是构建实时服务,例如股票,聊天室,在线游戏等实时性要求比较高的服务。
在这里插入图片描述

为什么要用 Web API

Web API最重要的是可以构建面向各种客户端的服务。另外与WCF REST Service不同在于,Web API利用Http协议的各个方面来表达服务(例如 URI/request response header/caching/versioning/content format),因此就省掉很多配置。
在这里插入图片描述
当你遇到以下这些情况的时候,就可以考虑使用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很类似,他们有哪些不同之处呢?先上图,这就是他们最大的不同之处。
在这里插入图片描述
详细点说他们的区别,

  • 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 实战 (Web API + MongoDB + knockoutjs)

ASP.NET网站上有很多简单的Web API实例,看看贴图和实例代码你就明白怎么用了。这里我们通过一个稍微复杂一点的实例来展示下Web API的功能。
涉及技术
在我们的实例里面用到了:

  • Mongo DB数据库保存数据 (NoSQL, Document Store,跨平台,跨语言)
  • Web API提供数据服务
  • MVC作数据展示
  • Knockoutjs动态绑定客户端数据,这里有一个简单的介绍
    服务URI Pattern
    在这里插入图片描述

准备工作

  1. 下载并安装Mongo DB,步骤看这里

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

  3. 如果想本地察看数据库中内容,下载MongoVUE。

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

代码实现

  1. 创建项目

创建MVC4 Web Application
在这里插入图片描述
在Project Template中选择Web API
在这里插入图片描述
然后项目就创建成了,Controllers里面有一个ValuesController,是自动生成的一个最简单的Web API Controller。

正如我们前面所说,里面引用的是System.Web.Http命名空间。
在这里插入图片描述
2. 创建model

在model里面添加Contact类
在model里添加Contact类
代码如下,其中BsonId需要mongocsharpdriver。

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。
在这里插入图片描述
在这里插入图片描述
另外我们需要在Model中添加Repository,Controller通过该类来访问Mongo DB。

public interface IContactRepository { 
        IEnumerable GetAllContacts(); 
        Contact GetContact(string id); 
        Contact AddContact(Contact item); 
        bool RemoveContact(string id); 
        bool UpdateContact(string id, Contact item);   
    }

ContactRepository的完整实现如下,

 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;
    }
}
  1. 添加Controller

右键Controllers目录选择添加Controller
在这里插入图片描述
选择Empty API controller,将Controller命名为ContactsController
在这里插入图片描述
添加如下代码,可以看到Controller中的API方法名就是以http verb命名的。

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);
        }
    }
}
  1. 添加View

首先添加Knockoutjs库,
在这里插入图片描述
Knockoutjs通过MVVM模式来实现动态html绑定数据,如下图,其中View-Model是客户端的javascript object保存的model数据。
在这里插入图片描述
先打开HomeController,里面添加一个新的Action代码如下,因为我们要在MVC中对于ContactsController添加对应的View。

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

然后右键Admin方法,选择添加View
在这里插入图片描述
选择Create strongly-typed view,在model class中选择Contact类。
在这里插入图片描述
添加View的完整代码,注意view中我们通过js去访问WebAPI,以及通过动态绑定将数据呈现在网页上。

@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页面的链接如下

<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>
  1. 测试与调试

大功告成,直接运行下我们的作品,我们的admin链接也显示在右上角,
在这里插入图片描述
Admin页面的样子,Contact list是动态加载进来的,可以通过这个页面做添加,修改,删除的操作。
在这里插入图片描述
通过IE network capture来查看请求内容,

重新加载页面,可以看到回复的格式为JSON,
在这里插入图片描述
JSON内容就是我们mock的一些数据。
在这里插入图片描述
接下来我们修改,删除,又添加了一条记录,可以看到使用了不同的http method。
在这里插入图片描述
通过前面安装的mongovue来查看下DB中的数据,先添加的user也在其中,令我感到欣慰。。。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/schc380339655/article/details/87915498