ASP.NET WebApi 开放数据

2020-11-26 18:23

阅读:528

标签:style   blog   class   code   c   tar   

概述

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

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

项目搭建

    soscw.com,搜素材

添加模型

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace ApiDemo02.Models
{
    /// 产品实体类
    public class Product
    {
        /// 产品ID
        public int ID { get; set; }
 
        /// 产品名称
        public string Name { get; set; }
 
        /// 产品类别
        public string Genre { get; set; }
 
        /// 产品价格
        public decimal Price { get; set; }
    }
}

  注:先生成一下项目!

添加模型

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

     soscw.com,搜素材

     soscw.com,搜素材

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

     soscw.com,搜素材

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

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

     soscw.com,搜素材   

修改配置

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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("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 中的通过添加属性、 键和导航属性。

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

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

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

?
1
2
3
4
5
6
  "ProductContext"
       connectionString="Data Source=(localdb)\v11.0; Initial Catalog=ProductDB; Integrated Security=True;
       MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|ProductDB.mdf"
    providerName="System.Data.SqlClient" />

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

迁移及初始化数据库

      打开VS“工具”:

      soscw.com,搜素材

      查看迁移帮助:

      soscw.com,搜素材

      启用迁移:

      soscw.com,搜素材 

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

      soscw.com,搜素材

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using ApiDemo02.Models;
using System.Data.Entity.Migrations;
 
namespace ApiDemo02.Migrations
{
    internal sealed class Configuration : DbMigrationsConfiguration
    {
        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" },
            });
        }
    }
}

  添加迁移:

      soscw.com,搜素材

      更新数据库:

      soscw.com,搜素材

      检查数据库文件:

      soscw.com,搜素材

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

访问测试

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

      运行项目,看一下端口:

      soscw.com,搜素材

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

      打开fiddler,点Composer:

      soscw.com,搜素材

      点Execute后,并查看xml结果:

      soscw.com,搜素材  

      响应json请求:

      soscw.com,搜素材

      查看结果:

      soscw.com,搜素材

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

      soscw.com,搜素材  

      查看结果:

      soscw.com,搜素材

      读取Product数据:

      soscw.com,搜素材

      查看数据:

      soscw.com,搜素材

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

小结

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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");
    config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
    */
    public class ProductController : ODataController
    {
        private ProductContext db = new ProductContext();
 
        // GET odata/Product
        [Queryable]
        public IQueryable GetProduct()
        {
            return db.Products;
        }
 
        // GET odata/Product(5)
        [Queryable]
        public SingleResult 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 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序列化/格式化,有空再介绍。

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

       

         

ASP.NET WebApi 开放数据,搜素材,soscw.com

ASP.NET WebApi 开放数据

标签:style   blog   class   code   c   tar   

原文地址:http://www.cnblogs.com/fanjibao/p/3726458.html


评论


亲,登录后才可以留言!