C#:如何在API控制器级别应用序列化以获得某些列
我们目前有存储库层和应用程序服务层C#:如何在API控制器级别应用序列化以获得某些列,c#,.net,asp.net-core,serialization,repository,C#,.net,Asp.net Core,Serialization,Repository,我们目前有存储库层和应用程序服务层 Repo使用实体框架从SQLServer数据库获取数据 应用服务层收集数据,并做更多的事情:发送电子邮件,解析平面文件 回购层 public Task<Sales> GetBySalesId(int salesId) { var salesData = _context.Sales .Include(c => c.Customer) .FirstOrDefaultAsync(c => c.Sale
public Task<Sales> GetBySalesId(int salesId)
{
var salesData = _context.Sales
.Include(c => c.Customer)
.FirstOrDefaultAsync(c => c.SalesId == salesId);
return salesData ;
}
public async Task<ActionResult<SalesDto>> GetSalesBySalesId(string salesId)
{
var dto = await _service.GetBySalesId(salesId);
return Ok(dto);
}
public async Task<ActionResult<SalesDto>> GetSalesBySalesId(string salesId)
{
UISalesTable dto = await (UISalesTable) _service.GetSales(new GetSalesForUICommand
{
SalesId = salesId,
IncludeProductType = true,
IncludeCustomer = false
});
return Ok(dto);
}
public async Task<ActionResult<MonthlySales>> GetSalesReport(string salesId)
{
MonthlySales dto = await (MonthlySales) _service.GetSales(new GetMonthlySalesReportCommand
{
SalesId = salesId,
// extra filters goes here
});
return Ok(dto);
}
公共任务GetBySalesId(int-salesId)
{
var salesData=\u context.Sales
.包括(c=>c.客户)
.FirstOrDefaultAsync(c=>c.SalesId==SalesId);
返回销售数据;
}
服务层:
public async Task<SalesDto> GetSalesByIdAppService(int salesId)
{
var salesData = await _salesRepository.GetBySalesId(salesId);
var salesDto = _mapper.Map<SalesDto>(salesData);
return salesDto;
}
public Task<Sales> GetBySalesId(int salesId)
{
var salesData = _context.Sales
.Include(c => c.Customer)
.Include(c => c.ProductType)
.Include(c => c.Employee)
.FirstOrDefaultAsync(c => c.SalesId == salesId);
return salesData ;
}
公共异步任务GetSalesByIdAppService(int-salesId)
{
var salesData=await\u salesRepository.GetBySalesId(salesId);
var salesDto=_mapper.Map(salesData);
将salesDto退回;
}
这是目前工作良好。然而明天,我的一位同事可能需要更多的专栏,而我的应用程序的特定部分不需要这些专栏
这里又添加了两个Linq包含:但是,我不需要产品或员工
新增回购协议:
public async Task<SalesDto> GetSalesByIdAppService(int salesId)
{
var salesData = await _salesRepository.GetBySalesId(salesId);
var salesDto = _mapper.Map<SalesDto>(salesData);
return salesDto;
}
public Task<Sales> GetBySalesId(int salesId)
{
var salesData = _context.Sales
.Include(c => c.Customer)
.Include(c => c.ProductType)
.Include(c => c.Employee)
.FirstOrDefaultAsync(c => c.SalesId == salesId);
return salesData ;
}
公共任务GetBySalesId(int-salesId)
{
var salesData=\u context.Sales
.包括(c=>c.客户)
.包括(c=>c.ProductType)
.包括(c=>c.员工)
.FirstOrDefaultAsync(c=>c.SalesId==SalesId);
返回销售数据;
}
背景一个建议是创建另一个每个人都可以利用的中间域层。在API DTO级别,每个人都可以有单独的DTO,它只从域中收集所需的类成员。这实质上需要创建另一层,其中DTO是新“域”层的子集
*另一个建议是只对需要的列应用序列化。我一直听说这件事,但是,怎么能做到呢?是否可以在不添加其他层的情况下将应用程序序列化到控制器API?Newtonsoft是否有工具或C#中的任何语法
API控制器
public Task<Sales> GetBySalesId(int salesId)
{
var salesData = _context.Sales
.Include(c => c.Customer)
.FirstOrDefaultAsync(c => c.SalesId == salesId);
return salesData ;
}
public async Task<ActionResult<SalesDto>> GetSalesBySalesId(string salesId)
{
var dto = await _service.GetBySalesId(salesId);
return Ok(dto);
}
public async Task<ActionResult<SalesDto>> GetSalesBySalesId(string salesId)
{
UISalesTable dto = await (UISalesTable) _service.GetSales(new GetSalesForUICommand
{
SalesId = salesId,
IncludeProductType = true,
IncludeCustomer = false
});
return Ok(dto);
}
public async Task<ActionResult<MonthlySales>> GetSalesReport(string salesId)
{
MonthlySales dto = await (MonthlySales) _service.GetSales(new GetMonthlySalesReportCommand
{
SalesId = salesId,
// extra filters goes here
});
return Ok(dto);
}
公共异步任务GetSalesBySalesId(字符串salesId)
{
var dto=await\u service.GetBySalesId(salesId);
返回Ok(dto);
}
JSON Ignore可能不起作用,因为我们都共享相同的DTO,并且应用程序的另一部分可能需要忽略一个区域。使用[JsonIgnore]属性装饰类中的成员,这些属性在响应中不需要。JsonIgnore在中提供 System.Text.Json.Serialization命名空间
public class SalesDto
{
[JsonIgnore]
public string Customer { get; set; }
public string ProductType { get; set; }
public string Employee { get; set; }
}
将模型的所有属性与数据绑定,当您将其发送到UI时,客户属性将无法响应
我们应该从数据库中获取所有数据,并在表示层中处理这些数据。GraphQL可能是该场景的赢家,但需要探索,因为中间域层有助于支持此类需求。它使调用者能够控制返回的对象图的形状。实现这一点的代码太复杂,无法作为一篇文章包含在内,但是这些类型的需求通常可以通过实现专门为处理它们而设计的体系结构来更好地解决,而不是采用自己的快速修复方法
- 您还可以看到,这允许在返回数据的形状上具有更大的灵活性,但是对于服务器端和客户端来说,这是一条更陡峭的学习曲线
JsonIgnore
的问题在于,这是DTO上的一个永久性定义,这会使可能需要不同数据形状/视图的不同应用程序很难使用相同的DTO定义
该问题的解决方案是为每个应用程序创建一个紧密耦合的DTO分支,该分支继承自基础,但通过使用JsonIgnore
属性装饰属性来覆盖属性
如果希望避免UI在数据模型上强制执行太多结构的紧密耦合场景,这将使维护数据模型变得更加困难,并可能导致许多其他反模式
允许一组在后端和客户端中具有一致结构的DTO,同时允许客户端减少/省略/忽略其不知道或不希望传输的字段 这里的关键是客户机现在可以(部分)控制图形,而不是API需要预测或严格定义每个应用程序必须使用的特定属性 这意味着许多现成的产品可以直接与API集成 需要考虑的一些建议:
- 编写一次,定义所有应用程序都可以访问的数据模型的完整结构
- 客户端可以通过指定所需的字段
- 这是所有API/服务层的一个特性,但是OData有一个支持和记录定制业务的标准约定
- OData序列化程序可以配置为仅传输跨线路具有值的属性
- 调用者可以指定在查询结果中包含哪些字段
- 您可以配置默认属性和导航链接,以便在客户端未指定投影时发送资源请求
- OData有一个简单的机制来支持对对象的部分更新,您只需通过连线发送任何对象的更改属性
- 当然,这确实是前一点的一部分,但它确实是在基于标准REST的API上使用OData的有力论据
- 您可以轻松地将业务规则注入到查询验证管道(或执行)中,以达到prev