前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET Core开发实战(第31课:APIController:定义API的最佳实践)--学习笔记

.NET Core开发实战(第31课:APIController:定义API的最佳实践)--学习笔记

作者头像
郑子铭
发布2021-01-13 15:32:44
1.3K0
发布2021-01-13 15:32:44
举报

31 | APIController:定义API的最佳实践

首先看一个传统意义上三层架构定义的 Controller

代码语言:javascript
复制
[HttpPost]
public Task<long> CreateOrder([FromBody]CreateOrderVeiwModel viewModel)
{
    var model = viewModel.ToModel();
    return await orderService.CreateOrder(model);
}


class OrderService : IOrderService
{
    public long CreateOrder(CreateOrderModel model)
    {
        var address = new Address("wen san lu", "hangzhou", "310000");
        var order = new Order("xiaohong1999", "xiaohong", 25, address);

        _orderRepository.Add(order);
        await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
        return order.Id;
    }
}

可以看到这里的 Controller 负责模型转换,还负责服务调用,服务里面实际上就是领域模型的操作部分

随着业务逻辑的越来越复杂,Controller 会越来越膨胀,在 DDD 领域驱动设计的理念下,我们更倾向于把应用程序的每一层明确区分,然后层与层之间的界限应该是明确的,在实现上面应该也是隔离的

Controller 这一层负责与前端用户的交互,它主要的责任就是定义输入和输出,实现身份认证,授权功能,它不应该处理领域模型,处理仓储,所以不建议以上的写法,不建议在 Controller 里面写模型转换和服务调用

代码语言:javascript
复制
namespace GeekTime.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class OrderController : ControllerBase
    {
        IMediator _mediator;
        public OrderController(IMediator mediator)
        {
            _mediator = mediator;
        }

        [HttpPost]
        public async Task<long> CreateOrder([FromBody]CreateOrderCommand cmd)
        {
            return await _mediator.Send(cmd, HttpContext.RequestAborted);
        }



        [HttpGet]
        public async Task<List<string>> QueryOrder([FromBody]MyOrderQuery myOrderQuery)
        {
            return await _mediator.Send(myOrderQuery);
        }
    }
}

这里使用了中间者模式 Mediator,它通过把命令发送出去,然后我们在 Commands 目录下面定义了每一个命令的 handler,这样就可以将业务逻辑的部分和 Controller 处理的部分,输入输出定义的部分进行隔离,我们的 Controller 还需要去定义路由的规则,路由验证的规则

再看一下 Controller 的构造函数,从设计上建议 Controller 所依赖的服务都通过它的构造函数注入进来,之前有讲过,通过容器进行属性注入的方式,但这种方式我们并不推荐使用,当一个 Controller 依赖了很多服务的时候,可以发现有一部分服务是大部分的 Action 都会依赖到的,有一部分服务只是个别 Action 依赖到的,这个时候就可以使用 FromServices,而不需要在构造函数里面注入它,这样有个好处是在编写单元测试的时候,可以在容器里面 Mock 所有的服务

代码语言:javascript
复制
public async Task<long> CreateOrder([FromServices] IEventBus eventBus, [FromBody]CreateOrderCommand cmd)

这里不建议使用属性注入的方式来注入服务,是因为使用属性注入的时候,会把这些属性,比如说 IOrderService,有可能由其他代码 set 我们的 OrderService,造成意外的情况,使我们的代码的维护不可控

代码语言:javascript
复制
public IOrderService orderService { get; set; }

还有一个关键的点是建议尽可能定义异步的 action,尽可能地使用 async 和 await 这样的组合来实现我们的代码,这样对提高我们应用程序的吞吐量是有一定的帮助的

总结一下

APIController 实际上是负责了对前端用户的输入输出的定义,它还负责了身份验证,授权,Url 定义的部分

APIController 不应该负责业务逻辑的承载,应该把这些职责交给我们命令处理程序或者说领域服务来定义

再一个我们也讲解了 APIController 在注入服务时的一些方法,通过构造函数的注入,通过 FromServices 的方式获取服务,不建议的做法时使用属性注入的方式注入

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 31 | APIController:定义API的最佳实践
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档