• ASP.NET WebApi 开放数据


    概述

          开放式数据协议(OData) 是用于在 web 数据访问协议。它提供统一的方式来构造数据、 查询的数据和操纵数据集通过 CRUD 操作。它支持 AtomPub (XML) 和 JSON 格式。它还定义的方式来公开元数据有关的数据。客户端可以使用元数据来发现的类型信息和数据集的关系。

          ASP.NET Web API 容易地创建一个数据集的 OData 终结点。您可以控制到底哪些 OData 操作终结点支持。你可以承载多个 OData 端点,除了非 OData 端点。你有你的数据模型后, 端业务逻辑和数据层的完全控制。

    项目搭建

       

    添加模型

        在Models文件夹下,添加Product.cs:           

    namespace ApiDemo02.Models
    {
        /// <summary>产品实体类</summary>
        public class Product
        {
            /// <summary>产品ID</summary>
            public int ID { get; set; }
    
            /// <summary>产品名称</summary>
            public string Name { get; set; }
    
            /// <summary>产品类别</summary>
            public string Genre { get; set; }
    
            /// <summary>产品价格</summary>
            public decimal Price { get; set; }
        }
    }
    

      注:先生成一下项目!

    添加模型

         在 Controllers文件夹下,添加控制器:

         

         

         点击“添加”,则出现下面错误:

         

         原因:前面我提示过,创建新实体后,先生成一下项目。这里我还是忘记了,生成项目后,再照上面步骤添加控制器,ok!

         支架自动创建了两个文件:

            

    修改配置

         打开App_Start文件下的WebApiConfig.cs,修改代码:   

    using ApiDemo02.Models;
    using System.Web.Http;
    using System.Web.Http.OData.Builder;
    
    namespace ApiDemo02
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                //创建 OData 端点的实体数据模型 (EDM)
                ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
                //添加设置为 EDM 实体
                builder.EntitySet<Product>("Products");
                //添加终结点的路由
                config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
    
                // Web API routes
                //config.MapHttpAttributeRoutes();
    
                //config.Routes.MapHttpRoute(
                //    name: "DefaultApi",
                //    routeTemplate: "api/{controller}/{id}",
                //    defaults: new { id = RouteParameter.Optional }
                //);
            }
        }
    }
    

      EDM 是一种抽象的数据模型。EDM 用于创建元数据文件和定义服务的 Uri。ODataConventionModelBuilder通过使用一组默认的命名约定 EDM 创建 EDM,这种方法要求最少代码。如果你想对 EDM 的更多控制,你可以使用ODataModelBuilder类来显式地创建 EDM 中的通过添加属性、 键和导航属性。

          EntitySet<Product>("Product")中"Product"的字符串定义是控制器的名称。终结点可以有多个实体集。EntitySet < T >对应一个实体集,然后再定义一个对应的控制器。

          MapODataRoute方法第一个参数是路线的友好名称。您服务的客户端看不到此名称。第二个参数是为终结点的 URI 前缀。鉴于此代码,为产品实体集的 URI 是 http:// /odata/Product。您的应用程序可以有多个 OData 端点。对于每个终结点,调用MapODataRoute ,并提供一个独特的路由名称和唯一的 URI 前缀。

          在修改一下根目录下的Web.config中的<connectionStrings>数据库连接字符串节点:

      <connectionStrings>
        <add name="ProductContext"
             connectionString="Data Source=(localdb)v11.0; Initial Catalog=ProductDB; Integrated Security=True; 
             MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|ProductDB.mdf"
          providerName="System.Data.SqlClient" />
      </connectionStrings>
    

          注:这一小节EDM有点难理解,我也得好好琢磨一下!

    迁移及初始化数据库

          打开VS“工具”:

          

          查看迁移帮助:

          

          启用迁移:

           

          这时,会多出Migrations文件夹及其下Configuration.cs文件:

          

          修改Migrations文件夹下Configuration.cs文件来添加种子数据:      

    using ApiDemo02.Models;
    using System.Data.Entity.Migrations;
    
    namespace ApiDemo02.Migrations
    {
        internal sealed class Configuration : DbMigrationsConfiguration<ApiDemo02.Models.ProductContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(ApiDemo02.Models.ProductContext context)
            {
                context.Products.AddOrUpdate(new Product[]
                {
                    new Product() { ID = 1, Name = "Hat", Price = 15, Genre = "Apparel" },
                    new Product() { ID = 2, Name = "Socks", Price = 5, Genre = "Apparel" },
                    new Product() { ID = 3, Name = "Scarf", Price = 12, Genre = "Apparel" },
                    new Product() { ID = 4, Name = "Yo-yo", Price = 4.95M, Genre = "Toys" },
                    new Product() { ID = 5, Name = "Puzzle", Price = 8, Genre = "Toys" },
                });
            }
        }
    }
    

      添加迁移:

          

          更新数据库:

          

          检查数据库文件:

         

          至此,数据库创建OK,也有了模拟数据!

    访问测试

          这里使用HTTP工具来模拟请求,所以先去下载(http://www.telerik.com/fiddler)安装Fiddler4。

          运行项目,看一下端口:

          

          注:这里Chrome浏览器以xml方式读取,如果使用IE浏览器,它默认是json方式,会提示下载!

          打开fiddler,点Composer:

          

          点Execute后,并查看xml结果:

            

          响应json请求:

          

          查看结果:

          

          获取元数据,不论是否json请求,它返回xml格式: 

            

          查看结果:

          

          读取Product数据:

          

          查看数据:

          

          由于截图太多了,我就不演示POST等其它请求了! 

    小结

          回顾一下Cntrollers下ProductController.cs的代码:      

    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Web.Http;
    using System.Web.Http.ModelBinding;
    using System.Web.Http.OData;
    using ApiDemo02.Models;
    
    namespace ApiDemo02.Controllers
    {
        /*
        若要为此控制器添加路由,请将这些语句合并到 WebApiConfig 类的 Register 方法中。请注意 OData URL 区分大小写。
    
        using System.Web.Http.OData.Builder;
        using ApiDemo02.Models;
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Product>("Product");
        config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
        */
        public class ProductController : ODataController
        {
            private ProductContext db = new ProductContext();
    
            // GET odata/Product
            [Queryable]
            public IQueryable<Product> GetProduct()
            {
                return db.Products;
            }
    
            // GET odata/Product(5)
            [Queryable]
            public SingleResult<Product> GetProduct([FromODataUri] int key)
            {
                return SingleResult.Create(db.Products.Where(product => product.ID == key));
            }
    
            // PUT odata/Product(5)
            public IHttpActionResult Put([FromODataUri] int key, Product product)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                if (key != product.ID)
                {
                    return BadRequest();
                }
    
                db.Entry(product).State = EntityState.Modified;
    
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!ProductExists(key))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
    
                return Updated(product);
            }
    
            // POST odata/Product
            public IHttpActionResult Post(Product product)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                db.Products.Add(product);
                db.SaveChanges();
    
                return Created(product);
            }
    
            // PATCH odata/Product(5)
            [AcceptVerbs("PATCH", "MERGE")]
            public IHttpActionResult Patch([FromODataUri] int key, Delta<Product> patch)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                Product product = db.Products.Find(key);
                if (product == null)
                {
                    return NotFound();
                }
    
                patch.Patch(product);
    
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!ProductExists(key))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
    
                return Updated(product);
            }
    
            // DELETE odata/Product(5)
            public IHttpActionResult Delete([FromODataUri] int key)
            {
                Product product = db.Products.Find(key);
                if (product == null)
                {
                    return NotFound();
                }
    
                db.Products.Remove(product);
                db.SaveChanges();
    
                return StatusCode(HttpStatusCode.NoContent);
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    db.Dispose();
                }
                base.Dispose(disposing);
            }
    
            private bool ProductExists(int key)
            {
                return db.Products.Count(e => e.ID == key) > 0;
            }
        }
    }
    

      真的很神奇地采用数据库上下文帮我们封装好数据库操作!疑问:还有必要再封装成仓储库方式吗? 再有WebApi如何路由的和JSON序列化/格式化,有空再介绍。

         (注:截图过多,看起来花花绿绿地,抱歉了!)

           

             

  • 相关阅读:
    c++ range库
    差分数组
    简单比较一下C++中的引用和指针
    数字图像处理中一张常用图片
    内存池与内存块
    SmartPtr
    Allocator
    Java学习第12天
    Java学习第11天
    Java学习第10天
  • 原文地址:https://www.cnblogs.com/fanjibao/p/3726458.html
Copyright © 2020-2023  润新知