从我做起[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的扩展性非常灵活,可以无侵入源码加载自定 ...
随机推荐
- 常见分布式唯一ID生成策略
方法一: 用数据库的 auto_increment 来生成 优点: 此方法使用数据库原有的功能,所以相对简单 能够保证唯一性 能够保证递增性 id 之间的步长是固定且可自定义的 缺点: 可用性难以保证 ...
- ADAM : A METHOD FOR STOCHASTIC OPTIMIZATION
目录 概 主要内容 算法 选择合适的参数 一些别的优化算法 AdaMax 理论 代码 Kingma D P, Ba J. Adam: A Method for Stochastic Optimizat ...
- IM2605说明书| InmicroIM2605|IM2605芯片
IM2605描述 IM2605集成了一个同步4开关Buck-Boost变换器,在输入电压小于或大于输出电压时保持输出电压调节.当输入电压足够大于输出电压时,它作为Buck变换器工作,并随着输入电压接近 ...
- Linux-saltstack-2 saltstack的基本使用
@ 目录 一.salt命令的基本使用 1.基本语法 例子: 2.salt的常用参数 (1)-S(大写):通过IP或者是网段匹配被管理主机 (2)-E:通过正则匹配主机 (3)-L: 匹配多个主机 (4 ...
- shell2-if判断
1.条件测试类型(判断类型): 将测试结果做为判断依据. 测试类型有以下三种 [ 命令 ] :命令测试法(最常用的) [[ 命令 ]] : 关键字测试 test 命令 以上是三种都可以,注意单词 ...
- python + web自动化,点击不生效,提示“selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element is not clickable at point (117, 674)”
前言: 在做web自动化时,遇到一个缩放了浏览器比例的操作,从100%缩小到80%,再进行点击的时候,弹出报错信息,无法点击 selenium.common.exceptions.ElementCli ...
- vuex 中使用Element-ui的message
首先引入Message 其次,在mutations中调用Message 注意:缓存的问题,如果没有弹出框架出现,多重启几次服务 参考资料: https://blog.csdn.net/weixin_4 ...
- CentOS6.4安装Zookeeper-3.4.12图解教程
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6595380916590215683/ 安装工具 VMware_workstation_full_12.5.2 Ce ...
- MySQL使用时间作为判断条件
背景:在开发过程中,我们经常需要根据时间作为判断条件来查询数据,例如:当月,当日,当前小时,几天内...... 1. 当月 我们只需要使用一个mysql的MONTH(date)函数即可实现.(注意判断 ...
- [USB波形分析] 全速USB波形数据分析(三)
前面的两篇文章介绍和分析了USB的一些基本知识,结合前面的介绍,今天用实例介绍USB的枚举过程. 1 | 概况 硬件基于EK-TMC123GXL开发板,软件是TI提供的USB批量传输的简单例子,在PC ...