从我做起[AutoMapper实现模块化注册自定义扩展MapTo<>()].Net Core 之二
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 之二的更多相关文章
- WCF自定义扩展,以实现aop!
引用地址:https://msdn.microsoft.com/zh-cn/magazine/cc163302.aspx 使用自定义行为扩展 WCF Aaron Skonnard 代码下载位置: S ...
- 第十三节:HttpHander扩展及应用(自定义扩展名、图片防盗链)
一. 自定义扩展名 1. 前言 凡是实现了IHttpHandler接口的类均为Handler类,HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...
- Asp.Net Mvc 自定义扩展
目录: 自定义模型IModelBinder 自定义模型验证 自定义视图引擎 自定义Html辅助方法 自定义Razor辅助方法 自定义Ajax辅助方法 自定义控制器扩展 自定义过滤器 自定义Action ...
- TransactionScope事务处理方法介绍及.NET Core中的注意事项 SQL Server数据库漏洞评估了解一下 预热ASP.NET MVC 的VIEW [AUTOMAPPER]反射自动注册AUTOMAPPER PROFILE
TransactionScope事务处理方法介绍及.NET Core中的注意事项 作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.ht ...
- 演练:创建和注册自定义 HTTP 模块
本演练演示自定义 HTTP 模块的基本功能. 对于每个请求,都需要调用 HTTP 模块以响应 BeginRequest 和 EndRequest 事件. 因此,该模块在处理请求之前和之后运行. 如果 ...
- U9单据打印模板自定义扩展字段显示名称
UBF打印模板中,单据自定义扩展字段显示均为扩展字段值集值编码,而在实际运用过程中打印时需要显示扩展字段名称,具体实现方法如下 方式一:采用SQL系统定义函数[dbo].[fn_GetSegName] ...
- spring boot actuator端点高级进阶metris指标详解、git配置详解、自定义扩展详解
https://www.cnblogs.com/duanxz/p/3508267.html 前言 接着上一篇<Springboot Actuator之一:执行器Actuator入门介绍>a ...
- AbpVnext使用分布式IDistributedCache Redis缓存(自定义扩展方法)
AbpVnext使用分布式IDistributedCache缓存from Redis(带自定义扩展方法) 我的依赖包的主要版本以及Redis依赖如下 1:添加依赖 <PackageReferen ...
- 这个Dubbo注册中心扩展,有点意思!
今天想和大家聊聊Dubbo源码中实现的一个注册中心扩展.它很特殊,也帮我解决了一个困扰已久的问题,刚刚在生产中用了,效果很好,迫不及待想分享给大家. Dubbo的扩展性非常灵活,可以无侵入源码加载自定 ...
随机推荐
- 「算法笔记」状压 DP
一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...
- [Open Source]基于YOLOv3与Django框架的Web应用-YOLOv3_Detect_Web
YOLOv3_Detect_Web Use Yolov3 detect on Web 使用 YOLOv3(PyTorch 和 Django 实现)的对象检测应用程序. 网页和 REST API由Dja ...
- [算法笔记-题解]问题 D: 习题4-4 三个整数求最大值
问题 D: 习题4-4 三个整数求最大值 [命题人 : 外部导入] 时间限制 : 1.000 sec 内存限制 : 12 MB 题目描述 有3个整数a, b, c,由键盘输入,输出其中最大的数. 输入 ...
- Linux_at任务调度
基本介绍 一次性定时计划任务,由守护进程atd以后台模式执行,检查作业队列来进行 默认情况下,atd每60s检查一次作业队列 在使用at命令时,要确保atd进程的启动,用指令来查看 ps -ef | ...
- redis-ha手动切换slave节点为master
仅做个人记录,请慎重参考!! 问题描述:使用redis-ha启动了3个pod,现在还有一个pod正常运行,并且为slave(理论上第一个起来的pod应该为master) 通过info命令查看下图 尝试 ...
- Kafka集群安装Version1.0.1(自带Zookeeper)
1.说明 Kafka集群安装,基于版本1.0.1, 使用kafka_2.12-1.0.1.tgz安装包, 其中2.12是编译工具Scala的版本. 而且不需要另外安装Zookeeper服务, 使用Ka ...
- rsync配置文件讲解
1.安装rysnc 一般在安装系统时rsync是安装上(yum安装) 2. vim /etc/xinetd.d/rsync 在这个路径下有配置文件 service rsync { disabl ...
- js 简单版发布留言 案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- XPTH定位总结
xpath定位总结:nodename 选取此节点的所有子节点. / :从根节点选取.绝对定位 //:从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置. 相对定位(推荐使用相对定位) . :选取 ...
- 解决VirtualBox 运行时报内存不能written
在VirtualBox 虚拟机中安装系统的时候,突然报"0x00000000指令,该内存不能written",只能强制停止,这个问题要怎么解决呢? 解决办法是恢复系统主题3个dll ...