AutoMapper实现模块化注册自定义扩展MapTo<>()

  我们都知道AutoMapper是使用的最多的实体模型映射,如果没有AutoMapper做对象映射那么我们需要想一下是怎么写的,是不是很麻烦写起来很难受这种,自从有了AutoMapper我们的代码量是不是减少了很多,但是.NetCore中的AutoMapper需要配置Profile文件,但是我们这个每次都需要在Starup中去注册,这就很麻烦了,下面我这篇文章来讲一下我们不需要每次去注册,让他实现自动注入而不需要每次都手动注入。

上次回顾

在上篇文章讲了Sukt.Core框架的一个整体架构搭建和怎样实现模块化注册和批量注入,如果没有看过上篇文章的请查看【从我做起[原生DI实现模块化和批量注入].Net Core 之一】,本篇来讲进行AutoMapper的模块化注册;

阶段一

  上篇文章有讲到我们有一个自动注册的基类,那么我们这次来回顾一下上次的依赖注入也是重写的这个自动注册基类他就是SuktAppModuleBase,我们的AutoMapper类也是继承与SuktAppModuleBase然后重写它里面的方法;我们的基类方法里面其实就是Startup中的两个方法;我们首先先创建一个Sukt.Core.AutoMapper类库,里面包含一个类SuktMapperModuleBase类继承我们的SuktAppModuleBase,我们重写基类里面的方法在此之前我们先看一下自定义扩展,这个扩展有什么作用呢?其实他的作用就是相同字段不需要配置Profile文件,而不需要我们去进行构造函数注入或者创建一个静态对象,每次使用都要注入或者创建一个静态对象会很烦;所讲的不需要在构造函数注入或者创建静态对象;而是直接自定义扩展方法使用你的对象名称(点)出来的;我们先看使用例子

使用范例:

public async Task<bool> InsertAsync(DataDictionaryInputDto input)
{
input.NotNull(nameof(input));
var entity = input.MapTo<DataDictionaryEntity>();
}

阶段二

  在进行自动化注册之前我们需要在Sukt.Core.Shared中添加我们的AutoMapper扩展类这个扩展类就是我们的AutoMapperExtension扩展方法我们可以看一下这里面的源代码,主要包括以下这些SetMapper()、CheckMapper()、MapTo<TTarget>()、MapTo<TSource, TTarget>()、IEnumerable<TTarget> MapToList<TTarget>()、IQueryable<TOutputDto> ToOutput<TOutputDto>()方法;SetMapper(IMapper mapper)方法主要用来进行对象实例注入、CheckMapper()方法用来检测实例有没有创建成功;自定义扩展方法分为这些,具体里面的代码怎么实现下面;废话少说;直接上代码。

private static IMapper _mapper = null;
/// <summary>
/// 写入AutoMapper实例
/// </summary>
public static void SetMapper(IMapper mapper)
{
mapper.NotNull(nameof(mapper));
_mapper = mapper;
}
/// <summary>
/// 检查传入的实例
/// </summary>
private static void CheckMapper()
{
_mapper.NotNull(nameof(_mapper));
}
/// 将对象映射为指定类型
/// </summary>
/// <typeparam name="TTarget">要映射的目标类型</typeparam>
/// <param name="source">源对象</param>
/// <returns>目标类型的对象</returns>
public static TTarget MapTo<TTarget>(this object source)
{
CheckMapper();
source.NotNull(nameof(source)); return _mapper.Map<TTarget>(source);
}
/// <summary>
/// 使用源类型的对象更新目标类型的对象
/// </summary>
/// <typeparam name="TSource">源类型</typeparam>
/// <typeparam name="TTarget">目标类型</typeparam>
/// <param name="source">源对象</param>
/// <param name="target">待更新的目标对象</param>
/// <returns>更新后的目标类型对象</returns>
public static TTarget MapTo<TSource, TTarget>(this TSource source, TTarget target)
{
CheckMapper();
source.NotNull(nameof(source));
target.NotNull(nameof(target));
return _mapper.Map(source, target);
}
/// <summary>
/// 将数据源映射为指定<typeparamref name="TTarget"/>的集合
/// </summary>
/// <typeparam name="TTarget">动态实体</typeparam>
/// <param name="sources">数据源</param>
/// <returns></returns>
public static IEnumerable<TTarget> MapToList<TTarget>(this IEnumerable<object> sources)
{
CheckMapper();
sources.NotNull(nameof(sources));
return _mapper.Map<IEnumerable<TTarget>>(sources);
}
/// <summary>
/// 将数据源映射为指定<typeparamref name="TOutputDto"/>的集合
/// </summary>
/// <param name="source">数据源</param>
/// <param name="membersToExpand">成员展开</param>
public static IQueryable<TOutputDto> ToOutput<TOutputDto>(this IQueryable source,params Expression<Func<TOutputDto, object>>[] membersToExpand)
{
CheckMapper();
return _mapper.ProjectTo<TOutputDto>(source, membersToExpand);
}

以上就是自定义扩展方法,使用了这个之后我们不需要在使用AutoMapper的地方使用静态类或者注入属性了;

阶段三

现在看下实现AutoMapper模块化注册;上面说到了我们创建了一个Sukt.Core.AutoMapper类库在这个类库下面有一个SuktMapperModuleBase类,我们继承了SuktAppModuleBase类,现在重写基类里面ConfigureServices方法,先看下代码;

     /// <summary>
/// 重写SuktAppModuleBase
/// </summary>
/// <param name="service"></param>
/// <returns></returns>
public override IServiceCollection ConfigureServices(IServiceCollection service)
{
var assemblyFinder = service.GetOrAddSingletonService<IAssemblyFinder, AssemblyFinder>();
var assemblys = assemblyFinder.FindAll();
var suktAutoMapTypes = assemblys.SelectMany(x => x.GetTypes()).Where(s => s.IsClass && !s.IsAbstract && s.HasAttribute<SuktAutoMapperAttribute>(true)).Distinct().ToArray();
service.AddAutoMapper(mapper =>
{
this.CreateMapping<SuktAutoMapperAttribute>(suktAutoMapTypes, mapper);
},assemblys,ServiceLifetime.Singleton);
var mapper = service.GetService<IMapper>();//获取autoMapper实例
AutoMapperExtension.SetMapper(mapper);
return base.ConfigureServices(service);
}

使用静态扩展方法主要的代码其实这些代码;

var mapper = service.GetService<IMapper>();//获取autoMapper实例

AutoMapperExtension.SetMapper(mapper);

service.AddAutoMapper(mapper =>{ this.CreateMapping<SuktAutoMapperAttribute>(suktAutoMapTypes, mapper);},assemblys,ServiceLifetime.Singleton);

到这里我们还不算完成,因为还有一些代码没有实现;只写了扩展方法但是它怎么知道要转给谁呢;我们就要用到特性了

创建一个SuktAutoMapperAttribute特性这个名字不要和官方的相同,不然会冲突,特性里面包含一下代码,还有一些代码就不贴了,具体代码请看Github【Sukt.Core】和【Destiny.Core.Flow

   /// <summary>
/// 如果使用AutoMapper会跟官方冲突,所以在前面加了项目代号
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class SuktAutoMapperAttribute:Attribute
{
/// <summary>
/// 构造函数传值
/// </summary>
/// <param name="targetTypes"></param>
public SuktAutoMapperAttribute(params Type[] targetTypes)
{
targetTypes.NotNull(nameof(targetTypes));
TargetTypes = targetTypes;
}
/// <summary>
/// 类型数组
/// </summary>
public Type[] TargetTypes { get; private set; }
public virtual SuktAutoMapDirection MapDirection
{
get { return SuktAutoMapDirection.From | SuktAutoMapDirection.To; }
}
}

我们在SuktMapperModuleBase类中在添加一个静态方法,方法代码;

        /// <summary>
/// 创建扩展方法
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <param name="sourceTypes"></param>
/// <param name="mapperConfigurationExpression"></param>
private void CreateMapping<TAttribute>(Type[] sourceTypes, IMapperConfigurationExpression mapperConfigurationExpression)where TAttribute : SuktAutoMapperAttribute
{
foreach (var sourceType in sourceTypes)
{
var attribute = sourceType.GetCustomAttribute<TAttribute>();
if (attribute.TargetTypes?.Count() <= 0)
{
return;
}
foreach (var tatgetType in attribute.TargetTypes)
{
///判断是To
if (attribute.MapDirection.HasFlag(SuktAutoMapDirection.To))
{
mapperConfigurationExpression.CreateMap(sourceType, tatgetType);
}
///判断是false
if (attribute.MapDirection.HasFlag(SuktAutoMapDirection.From))
{
mapperConfigurationExpression.CreateMap(tatgetType, sourceType);
} }
}
}

使用的时候在我们的类上配置SuktAutoMapperAttribute要映射到那个对象;看下我的使用方法我这里的是把DataDictionaryInputDto转到DataDictionaryEntity类上;

这里有一点坑哦AutoMapper此方法仅支持相同字段映射;非相同字段还是需要自己写这个文件的,这个文件直接创建一个自己的类继承与AutoMapper的Profile就好,如果使用这个文件则不需要配置上面的特性;这里也会在程序运行时注入到容器内不需要管理实例;

到这里我们的AutoMapper模块化注册和自定义扩展已经完成了,

给个星星! ️

如果你喜欢这篇文章或者它帮助你, 请给 在Github上给Star~(辛苦星咯)


GitHub

Sukt.Core:https://github.com/GeorGeWzw/Sukt.Core

Destiny.Core.Flow:https://github.com/GeorGeWzw/Destiny.Core.Flow

 

从我做起[AutoMapper实现模块化注册自定义扩展MapTo<>()].Net Core 之二的更多相关文章

  1. WCF自定义扩展,以实现aop!

    引用地址:https://msdn.microsoft.com/zh-cn/magazine/cc163302.aspx  使用自定义行为扩展 WCF Aaron Skonnard 代码下载位置: S ...

  2. 第十三节:HttpHander扩展及应用(自定义扩展名、图片防盗链)

    一. 自定义扩展名 1. 前言 凡是实现了IHttpHandler接口的类均为Handler类,HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

  3. Asp.Net Mvc 自定义扩展

    目录: 自定义模型IModelBinder 自定义模型验证 自定义视图引擎 自定义Html辅助方法 自定义Razor辅助方法 自定义Ajax辅助方法 自定义控制器扩展 自定义过滤器 自定义Action ...

  4. TransactionScope事务处理方法介绍及.NET Core中的注意事项 SQL Server数据库漏洞评估了解一下 预热ASP.NET MVC 的VIEW [AUTOMAPPER]反射自动注册AUTOMAPPER PROFILE

    TransactionScope事务处理方法介绍及.NET Core中的注意事项   作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.ht ...

  5. 演练:创建和注册自定义 HTTP 模块

    本演练演示自定义 HTTP 模块的基本功能. 对于每个请求,都需要调用 HTTP 模块以响应 BeginRequest 和 EndRequest 事件. 因此,该模块在处理请求之前和之后运行. 如果 ...

  6. U9单据打印模板自定义扩展字段显示名称

    UBF打印模板中,单据自定义扩展字段显示均为扩展字段值集值编码,而在实际运用过程中打印时需要显示扩展字段名称,具体实现方法如下 方式一:采用SQL系统定义函数[dbo].[fn_GetSegName] ...

  7. spring boot actuator端点高级进阶metris指标详解、git配置详解、自定义扩展详解

    https://www.cnblogs.com/duanxz/p/3508267.html 前言 接着上一篇<Springboot Actuator之一:执行器Actuator入门介绍>a ...

  8. AbpVnext使用分布式IDistributedCache Redis缓存(自定义扩展方法)

    AbpVnext使用分布式IDistributedCache缓存from Redis(带自定义扩展方法) 我的依赖包的主要版本以及Redis依赖如下 1:添加依赖 <PackageReferen ...

  9. 这个Dubbo注册中心扩展,有点意思!

    今天想和大家聊聊Dubbo源码中实现的一个注册中心扩展.它很特殊,也帮我解决了一个困扰已久的问题,刚刚在生产中用了,效果很好,迫不及待想分享给大家. Dubbo的扩展性非常灵活,可以无侵入源码加载自定 ...

随机推荐

  1. HTML网页设计基础笔记 • 【第2章 排列页面内容】

    全部章节   >>>> 本章目录 2.1 音频标签和视频标签 2.1.1 音频标签 2.1.2 视频标签 2.2 列表.div 以及 span 标签 2.2.1 列表标签 2. ...

  2. Android物联网应用程序开发(智慧城市)—— 火焰监控界面开发

    效果: 布局代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns: ...

  3. Hexo博客部署到腾讯云服务器全过程(Nginx,证书,HTTPS),你要的这里都有

    背景 说来也惭愧,博客已经搭建很久了,一直免费的部署在 Coding 和 Github Pages 上,前者迁移到腾讯云 Serverless,导致原有的配置始终有问题,没时间仔细研究,刚好腾讯服务器 ...

  4. Spring 处理请求和响应相关的注解

    @Controller 默认返回 templates 目录下的 string.html 页面内容. 在方法中加上 @ResponseBody 注解,可以返回JSON.XML或自定义mediaType的 ...

  5. nignx-防盗链

    环境 主机                  IP            角色 centos6.5-1       192.168.3.10      源主机 centos6.5-2       19 ...

  6. lombok不支持enum类型

    今天在使用枚举时想着少写getter方法和构造方法,结果加上注解后说是只支持class类型 来自为知笔记(Wiz)

  7. [vscode] os.getcwd(),调试和命令行运行的结果不一致

    问题描述: 调试和命令行运行的时候工作目录不一致 这会导致一个问题,我想从上级目录导入模块的话,F5调试就会找不到模块,而命令行则没问题 那么我该如何调试呢? 目录结构: top  └ folder_ ...

  8. linux 【阿里云服务器】 配置 redis 的正确流程

    1.前言 我的域名备案前几天通过了,这篇随笔完整的记录 redis 的安装流程 与各种 问题 的 具体解决方案. 2.操作[跟着步骤来] (1)指令cd /usr/local 进入local文件夹里面 ...

  9. 使用 arguments 对象

    arguments 对象表示参数集合,它是一个伪类数组,拥有与数组相似的结构,可以通过数组下标的形式访问函数实参值,但是没有基础 Array 的原型方法. //函数没有定义形参,但是在函数体内通过 a ...

  10. Windwos上Mysql突然出现系统错误3,找不到系统路口

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6540869188678844935/ 问题出现: 调试系统时,突然发现数据库连接不上了,打开界面工具也发现连接不上 ...