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
只是负责处理requests
,model
,validation
和返回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请求进来之后,路由会把请求指向特定的action
,MVC 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
- 首先在接口
ICompanyRepository
添加一个方法
public interface ICompanyRepository
{
IEnumerable<Company> GetAllCompanies(bool trackChanges);
}
- 然后在实现层实现它
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();
}
- 然后来到
Service.Contracts
,创建接口
public interface ICompanyService
{
IEnumerable<Company> GetAllCompanies(bool trackChanges);
}
这里是直接从数据库层获取了所有的数据,但是这是个不好的做法,现在只是为了完成一个最简单的方法,后期会修改
- 然后是实现层
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;
}
}
}
- 最后,在
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
使用这个库来自动将两个实体之间映射,去除手动映射
- 在
Service
中安装包AutoMapper.Extensions.Microsoft.DependencyInjection
- 在主项目中配置
builder.Services.AddAutoMapper(typeof(Program));
- 在主项目中创建
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)));
}
}
- 然后修改
ServiceManager
,使用DI将转换服务注入 - 修改
CompanyService
,DI注入转换服务
标签:CORE,ASP,service,读书笔记,companies,trackChanges,public,API,GetAllCompanies 来源: https://www.cnblogs.com/huangwenhao1024/p/16383168.html