本文很多内容来自 链接
Napoléon本身已经写得很好了,但是出于对该内容学习的要求,自己还是重新做了一遍。
有一些新的东西,不过大多数都是他的,希望大家了解
1.引言
最近在找工作,然后就遇到了需要做前后端分离项目的公司,可惜因为自己没做过Web Api项目,因此没通过,今天就特地找文章来学习他。
对于前后端分离的项目来说,Web Api只是提供和数据库操作的功能,可以提供该功能的框架还有MVC和WCP,在这里将Web Api和他的2兄弟比较一下,加深理解
1.1 与MVC
我最开始以为Web Api就是没有返回视图的MVC,其实这样的想法是错误的;
1)首先Web Api是不能返回视图的,MVC可以
2)Web Api是通过Http动词来判断不同的操作(Post,Get,Put,Delete),MVC是通过路由中的Action名来判断不同操作。(更复杂的操作可以通过传参的不同来判断)
1.2 与Wcf
都是提供远程接口调用,但是两者都很大的不同
1)Wcf是使用SOAP协议,而Web Api是使用Http协议
2)Wcf一般传输数据的格式是xml,而Web Api一般是使用Json
2.Demo例子
这里使用的是MongoDB+Web Api+Knockoutjs
简单介绍一下另两个框架:
MongoDB是NoSql非关系型数据库,轻量级,而且数据基本上都放在内存访问,因此速度快,但是没有事务是硬伤,因此只能存储原子性的数据。
Knockoutjs是一个前端框架,使用的是MVVM的模式,数据绑定(就这方面来说Vue和他很像),也就是数据的改变会自动同步到Dom上。
功能很简单,就是对Contact的增删改查
2.1 安装MongoDB数据库和NosqlBooster for MongoDB(MongoDB的图形化处理程序)
2.2 VS2017新建一个Web Api项目
2.2.1 在Nuget中添加上对应的框架,如图
后者是MongoDB的驱动包。
2.2.2 在Models文件夹中添加Contact实体类,和对应的仓库
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; } } public interface IContactRepository { IEnumerable<Contact> GetAllContacts(); Contact GetContact(string id); Contact AddContact(Contact item); bool RemoveContact(string id); bool UpdateContact(string id, Contact item); } public class ContactRepository : IContactRepository { MongoClient _server = null; IMongoDatabase _database = null; IMongoCollection<Contact> _contacts = null; public ContactRepository(string connection) { if (string.IsNullOrWhiteSpace(connection)) { connection = "mongodb://localhost:27017"; } _server = new MongoClient(connection); _database = _server.GetDatabase("Contacts"); _contacts = _database.GetCollection<Contact>("contacts"); // Reset database and add some default entries var filter = Builders<Contact>.Filter.Where(a => 1 == 1); _contacts.DeleteMany(filter); 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<Contact> GetAllContacts() { return _contacts.Find(a => 1 == 1).ToList(); } public Contact GetContact(string id) { //IMongoQuery query = Query.EQ("_id", id); return _contacts.Find(a => a.Id == id).FirstOrDefault(); } public Contact AddContact(Contact item) { item.Id = Guid.NewGuid().ToString(); item.LastModified = DateTime.UtcNow; _contacts.InsertOne(item); return item; } public bool RemoveContact(string id) { var filter = Builders<Contact>.Filter.Where(a => a.Id == id); var result = _contacts.DeleteOne(filter); return result.DeletedCount == 1; } public bool UpdateContact(string id, Contact item) { var query = Builders<Contact>.Filter.Where(a => a.Id == id); item.LastModified = DateTime.UtcNow; var update = Builders<Contact>.Update .Set("Email", item.Email) .Set("LastModified", DateTime.UtcNow) .Set("Name", item.Name) .Set("Phone", item.Phone); var result = _contacts.UpdateOne(query, update); return result.ModifiedCount > 0; } }
2.2.3 在Controllers文件夹中添加对应的ContactsController如下
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); } } }
2.2.4 在HomeController中添加要调用该Api的控制器和对应的页面
public ActionResult Admin() { string apiUri = Url.HttpRouteUrl("DefaultApi", new { controller = "contacts", }); ViewBag.ApiUrl = new Uri(Request.Url, apiUri).AbsoluteUri.ToString(); return View(); }
/Views/Home/Admin.cshtml
@model WebApplication1.Models.Contact @{ ViewBag.Title = "Admin"; } @section Scripts { @Scripts.Render("~/bundles/jqueryval") <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-3.5.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>
2.2.5 最后重新编译后,就可以查看了
3.总结
其实用这个代码来体会MongoDB,Web Api和MVVM都挺不错的,感谢原作者
大家通过这个代码可以看到控制器中只有几个方法,Ajax调用的类型不一样,程序就会进入不同的方法,相信这是在做框架的时候微软作出的约定。如图
就好像MVC是通过路由去通过反射获取要执行的action方法一样,这里应该是在获取header类型的前提下通过反射获取对应的action名。
而且Api直接就会将对象数据转化成Json,不需要使用MVC那样的JsonResult
最后代码放在这里供大家学习 下载