ASP.NET Core OData 实践——Lesson1-1搭建服务(C#)

创建项目

我们使用Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.14.0创建一个asp.net core 空的项目。
在这里插入图片描述
解决方案名是Lesson。由于后续我们还会陆续创建其他类似项目,于是给项目命名为Lesson1。
在这里插入图片描述
为了方便后续访问,我们取消掉配置HTTPS
在这里插入图片描述

安装依赖

Microsoft.AspNetCore.OData 是一个用于在 ASP.NET Core 应用程序中实现 OData(Open Data Protocol)服务的官方库。我们可以在Package Manager Console(程序包管理控制台)中输入下面的指令以安装该库。

Install-Package Microsoft.AspNetCore.OData

在这里插入图片描述
在这里插入图片描述

编写代码

创建模型类

在项目中创建目录Models,然后创建两个类:Customer类和Order类。
在这里插入图片描述
Order是一个数据模型。在业务上,它表示一个订单信息。Id是订单的唯一标识,所以该属性使用了required约束,表示它不可以为空;Amount是订单的花费。

namespace Lesson1.Models
{
    public class Order
    {
        public required int Id { get; set; }
        public decimal Amount { get; set; }
    }
}

Customer也是一个数据模型。在业务上表示一个客户信息。除了唯一标识该客户的Id属性,还有姓名(Name)以及订单(Orders)。

订单表列属性Orders对应于EDM(Entiy Data Model)中的关系(Relationship),是导航属性(Navigation properties)

namespace Lesson1.Models
{
    using System.Collections.Generic;

    public class Customer
    {
        public required int Id { get; set; }
        public required string Name { get; set; }
        public List<Order>? Orders { get; set; }
    }
}

此时我们还不能分辨Customer和Order是Entity Type还是Entity Set。它们只是单纯定义了数据结构。

创建Controller

在项目中我们创建Controller目录,并创建一个CustomersController,让它继承于ODataController。
在这里插入图片描述
继承ODataController之后,CustomersController就可以自动支持 OData 的查询选项(如 $filter、$select、$orderby、$expand 等),无需手动解析这些参数。

using System.Reflection.Emit;

namespace Lesson1.Controllers
{
    using Lesson1.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.OData.Query;
    using Microsoft.AspNetCore.OData.Routing.Controllers;
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public class CustomersController : ODataController
    {
        private static Random random = new Random();
        // 生成 3 个客户,每个客户有 2 个订单
        private static readonly List<Customer> customers = [.. Enumerable.Range(1, 3).Select(idx => new Customer
            {
                Id = idx,
                Name = $"Customer {idx}",
                Orders = [.. Enumerable.Range(1, 2).Select(dx => new Order
                    {
                        Id = (idx - 1) * 2 + dx,
                        Amount = random.Next(1, 9) * 10
                    })]
            })];

        [EnableQuery]
        public ActionResult<IEnumerable<Customer>> Get()
        {
            return Ok(customers);
        }

        [EnableQuery]
        public ActionResult<Customer> Get([FromRoute] int key)
        {
            var item = customers.SingleOrDefault(d => d.Id.Equals(key));

            if (item == null)
            {
                return NotFound();
            }

            return Ok(item);
        }
    }
}

上面代码中,我们创建了3个Customer Entity,它们的Id分别是1、2、3。它们的名称分别是 Customer 1Customer 2Customer 3

每个Customer Entity有两个Order Entity,它们的Id也有一定的规律:1、3、5、7、9、11。但是Amount 值是随机的。

后面两个查询函数Get的入参不同,对应的URL也不同。

  • Get()方法对应于 /odata/Customers,支持OData 查询:如 $filter、$orderby 等。
  • Get([FromRoute] int key)对应于处理 /odata/Customers({key}) ,key 参数自动从路由中获取。

上述查询函数都是被[EnableQuery]修饰。 [EnableQuery]是 ASP.NET Core OData 提供的一个特性(Attribute),用于在控制器的 Action 方法上启用 OData 查询功能。它允许客户端在请求 URL 中使用 OData 查询参数(如 $filter、$select、$orderby、$top、$skip 等),并自动解析和应用这些查询参数到返回的数据集合上,无需手动处理。

编写主函数

在主文件Program.cs中,我们填入下面的代码。

using Lesson1.Models;
using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;

var builder = WebApplication.CreateBuilder(args);

// 提取 OData EDM 模型构建为方法,便于维护和扩展
static IEdmModel GetEdmModel()
{
    var modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.EntityType<Order>();
    modelBuilder.EntitySet<Customer>("Customers");
    return modelBuilder.GetEdmModel();
}

// 添加 OData 服务和配置
builder.Services.AddControllers().AddOData(options =>
    options.Select()
           .Filter()
           .OrderBy()
           .Expand()
           .Count()
           .SetMaxTop(null)
           .AddRouteComponents("odata", GetEdmModel())
);

var app = builder.Build();

app.UseRouting();

app.MapControllers();

app.Run();

ODataConventionModelBuilder的EntityType\<T\>()方法用于将一个数据模型(本例中是Order类)注册为Entity TypeEntitySet\<\>() 方法将一个数据模型(本例中是Customer类)注册为Entity Set
EntityType 只定义类型结构,不暴露为 OData 端点;EntitySet 定义集合,并将其暴露为 OData 端点(如 /odata/Customers),供客户端访问。
所以我们在后续编码时,对于每个要暴露的集合调用 EntitySet\<\>() ,而EntityType\<T\>()只在需要单独定义类型时使用(如复杂类型(Complex Types)导航属性(Navigation properties)等)。

代码地址

https://github.com/f304646673/odata/tree/main/csharp/Lesson/Lesson1

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

breaksoftware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值