zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    ubuntu 安装FoxitReader福昕阅读器(转载)
    添加中文字库
    操作系统常用调度算法(转载https://www.cnblogs.com/kxdblog/p/4798401.html)
    2802:小游戏利用bfs来实现
    2802:小游戏
    适合使用并行的一种bfs
    (转载)关于usr/bin/ld: cannot find -lxxx问题总结
    gcc5.4报错对‘std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()’未定义的引用
    centos7如何安装gcc5.4
    将含有makefile文件的源码加入Eclipse工程
  • 原文地址:https://www.cnblogs.com/gamov/p/10563477.html
Copyright © 2011-2022 走看看