写点什么

武装你的 WEBAPI-OData 与 DTO

作者:高端章鱼哥
  • 2023-07-05
    福建
  • 本文字数:1549 字

    阅读完需:约 5 分钟

本文属于 OData 系列文章

Intro


前面写了很多有关 OData 使用的文章,很多读者会有疑问,直接将实体对象暴露给最终用户会不会有风险?$expand 在默认配置的情况下,数据会不会有泄露风险?


答案是肯定的,由于 OData 的特性,提供给我们便捷同时也会带来一些风险。很多地方推荐使用 DTO 模式来隔离实体类与最终用户使用到类的关系,从而解决以上两个问题,OData 同样也适用。

DTO


DTO 代表 Data Transfer Object,是一种设计模式,用于在不同层之间传输数据。它通常用于将数据从一个应用程序的逻辑层传输到另一个应用程序的界面层或持久化层,以及在分布式系统中传输数据。


DTO 对象是纯数据对象,它包含要从一个应用程序传输到另一个应用程序的数据。它不包含业务逻辑或数据访问代码,因此它们不能直接与数据库交互或执行任何操作,而只是简单地保存数据。


DTO 对象通常由开发人员创建,并且可以根据需要进行扩展。它们可以包含各种属性和方法,以提供使用方便和更好的可读性。使用 DTO 对象可以降低耦合度,使不同层之间的数据传输更加简单和安全。

AutoMapper


我们需要将实体对象与 DTO 进行转换,对于需要转换数量不是很多的情况,直接编写一个转换函数就方便了。


public static class DeviceDataExtension{    public static DeviceDataDto ToDeviceDataDto(this Datum deviceData)    {        if (deviceData == null) return null;        DeviceDataDto deviceDataDto = new()        {            DataArray = deviceData.DataArray,            DeviceId = deviceData.DeviceId,            Timestamp = deviceData.Timestamp,            Id = Guid.NewGuid().ToString()        };        return deviceDataDto;    }}
复制代码


但是如果需要映射的属性很多,或者有很多对象的情况,建议使用对象映射工具:AutoMapper。基础用法不详细说了,讲讲对 OData 的支持。


首先安装对 OData 支持的包,由于我使用默认的 DI,还需要安装 DI 支持的包:


Install-Package AutoMapper.Extensions.Microsoft.DependencyInjectionInstall-Package AutoMapper.AspNetCore.OData.EFCore
复制代码


然后有三个要求:


  • 一定要对对象声明显示展开(explicit expansion)。

  • 调用 IMapper 的 GetAsync()或者 GetQueryAsync()方法。

  • 不能在 Controller 或者方法上使用[EnableQuery]特性:这个我熟,因为 GetQueryAsync()函数需要利用 ODataQueryOptions 参数,如果同时使用[EnableQuery]会导致对结果再进行一次筛选,导致返回数据错误。


代码:

        services.AddAutoMapper(option =>        {            option.CreateMap<Datum, DeviceDataDto>()            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => Guid.NewGuid().ToString()))            .ForPath(dest => dest.DataArray, opt => opt.MapFrom(src => src.DataArray))            .ForAllMembers(w => w.ExplicitExpansion());        });
public DeviceDatasController(IMapper mapper) { _mapper = mapper; } [HttpGet] [ProducesResponseType(typeof(IEnumerable<DeviceDataDto>), Status200OK)] public async Task<IActionResult> GetAsync(string key, ODataQueryOptions<DeviceDataDto> options) { var insp = await _context.DeviceData.Where(w => w.DeviceId == key).GetQueryAsync(_mapper, options); return Ok(insp); }
复制代码


这样,我们就可以正常使用 OData,同时也享受了的 DTO 的好处,即可以对 DeviceDataDto 使用的 OData 查询。使用的时候要注意,如果有导航属性,导航属性也需要配置映射。


参考资料:AutoMapper/AutoMapper.Extensions.OData: Creates LINQ expressions from ODataQueryOptions and executes the query. (github.com)

发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
武装你的WEBAPI-OData与DTO_OData_高端章鱼哥_InfoQ写作社区