Net Core教程

Ultimate ASP.NET CORE 6.0 Web API --- 读书笔记(4)

本文主要是介绍Ultimate ASP.NET CORE 6.0 Web API --- 读书笔记(4),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Handling GET Requests

本文内容来自书籍: Marinko Spasojevic - Ultimate ASP.NET Core Web API - From Zero To Six-Figure Backend Developer (2nd edition)

Controllers只是负责处理requestsmodelvalidation和返回responses给前端或者HTTP客户端

始终让业务逻辑不参与到Controllers

创建presentation Layer,目的是提供端点给系统,然后consumers可以和数据交互

我们没有在主项目中创建Controllers文件夹,然后创建控制器,而是创建Presentation Layer,这也是一个库,然后这个库引用Service.Contracts,最后主项目引用Presentation,这样Presentation就只是引用了接口,而不知道实现,DI是在主项目中完成

然后在Presentation中使用Microsoft.AspNetCore.Mvc.Core包,为了在Presentation创建控制器

[Route("api/[controller]")]
[ApiController]
public class CompaniesController : ControllerBase
{

}

[Route("api/[controller]")]是属性路由

当HTTP请求进来之后,路由会把请求指向特定的actionMVC framework会解析HTTP请求并尝试匹配

框架中,由两种路由的实现

  • Convention-based routing
    • 第一段是映射控制器的name
    • 第二段是映射action
    • 第三段是被用来可选参数
      (Web API不使用这种形式的路由)如果使用这种路由,同时需要添加UseRouting中间件,而在AP
      I中,已经在MapControllers中配置路由
  • Attribute routing

4.2 Naming Our Resources

URI的资源名称应该总是一个名词而不是动词

当两个资源之间有依赖关系的时候,资源的URI应该是
/api/principalResource/{principalId}/dependentResource.

比如/api/companies/{companyId}/employees
因为employees不能单独存在

4.3 Getting All Companies From the Database

在这里,会开始添加一点实际业务逻辑进来

现在要实现的API是获取全部的Companies

  1. 首先在接口ICompanyRepository添加一个方法
public interface ICompanyRepository
{
    IEnumerable<Company> GetAllCompanies(bool trackChanges);
}
  1. 然后在实现层实现它
internal sealed class CompanyRepository : RepositoryBase<Company>, ICompanyRepository
{
    public CompanyRepository(RepositoryContext repositoryContext)
    :base(repositoryContext)
    {
    }
    public IEnumerable<Company> GetAllCompanies(bool trackChanges) =>
            FindAll(trackChanges)
                .OrderBy(c => c.Name)
                .ToList();
}
  1. 然后来到Service.Contracts,创建接口
public interface ICompanyService
{
    IEnumerable<Company> GetAllCompanies(bool trackChanges);
}

这里是直接从数据库层获取了所有的数据,但是这是个不好的做法,现在只是为了完成一个最简单的方法,后期会修改

  1. 然后是实现层Service
internal sealed class CompanyService : ICompanyService
{
    private readonly IRepositoryManager _repository;
    private readonly ILoggerManager _logger;

    public CompanyService(IRepositoryManager repository, ILoggerManager logger)
    {
        _repository = repository;
        _logger = logger;
    }
    public IEnumerable<Company> GetAllCompanies(bool trackChanges)
    {
        try
        {
            var companies = _repository.Company.GetAllCompanies(trackChanges);
            return companies;
        }
        catch (Exception ex)
        {
            _logger.LogError($"Something went wrong in the {nameof(GetAllCompanies)} service method {ex}");
            throw; 
        } 
    } 
}
  1. 最后,在Presentation中,使用这个方法返回结果
[Route("api/companies")]
[ApiController]
public class CompaniesController : ControllerBase
{
    private readonly IServiceManager _service;
    public CompaniesController(IServiceManager service) => _service = service;

    [HttpGet]
    public IActionResult GetCompanies()
    {
        try
        {
            var companies =  
                _service.CompanyService.GetAllCompanies(trackChanges: false);
            return Ok(companies);
        }
        catch
        {
            return StatusCode(500, "Internal server error");
        } 
    } 
}

4.5 DTO Classes vs. Entity Model Classes

上面说过,经过API请求直接返回数据库的实体类型,不是一个好的处理,需要一个DTO来替代

  • 为什么需要DTO
    因为Model主要是用来给EF Core来映射到数据库的,而且,一般Model是会有导航属性的,但是我们不希望返回给客户端。

    还有就是,当我们迁移数据库的时候,实体也被修改了,但是这并不代表我们的API会被修改。一般API制定之后不会经常被修改,它是一种协议

现在,创建一个Shared库,用作公共资源,创建DataTransferObjects/CompanyDto来转换Model

public record CompanyDto(Guid Id, string Name, string FullAddress);

然后替换Service.Contracts中的Entities引用

4.6 Using AutoMapper in ASP.NET Core

使用这个库来自动将两个实体之间映射,去除手动映射

  1. Service中安装包AutoMapper.Extensions.Microsoft.DependencyInjection
  2. 在主项目中配置builder.Services.AddAutoMapper(typeof(Program));
  3. 在主项目中创建profile文件,用于指定映射的src和des
public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Company, CompanyDto>()
            .ForMember(c => c.FullAddress, 
                opt => opt.MapFrom(x => string.Join(' ', x.Address, x.Country)));
    } 
}
  1. 然后修改ServiceManager,使用DI将转换服务注入
  2. 修改CompanyService,DI注入转换服务
这篇关于Ultimate ASP.NET CORE 6.0 Web API --- 读书笔记(4)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!