Web Api 简单例子(WebApi+MongoDB+Knockoutjs)

本文很多内容来自 链接

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>
View Code

2.2.5 最后重新编译后,就可以查看了

3.总结

其实用这个代码来体会MongoDB,Web Api和MVVM都挺不错的,感谢原作者

大家通过这个代码可以看到控制器中只有几个方法,Ajax调用的类型不一样,程序就会进入不同的方法,相信这是在做框架的时候微软作出的约定。如图

就好像MVC是通过路由去通过反射获取要执行的action方法一样,这里应该是在获取header类型的前提下通过反射获取对应的action名。

而且Api直接就会将对象数据转化成Json,不需要使用MVC那样的JsonResult

最后代码放在这里供大家学习  下载

原文地址:https://www.cnblogs.com/gamov/p/10563477.html