为了说明AutoMapper如何使用,我专门开设了一个专题来讲,如果您还没有查看该专题,请点击这里。既然系统地学习了AutoMapper,那么接下来就是该用它实战的时候了。今天,我们就来揭开AutoMapper如何在ABP框架中使用的面纱。
因为这里演示的是用ABP框架搭建的项目,本博客的讲解的前提是假设你有了ABP基础,所以,如果您还不了解ABP框架,请查看我的ABP框架的系列博客,请点击这里。
下面正式开始今天的讲解。
首先,让我们稍微回忆一下AutoMapper的知识点。
问:什么是AutoMapper?
答:AutoMapper翻译过来就是“自动映射工具”。它的作用就是将一个源类型映射成一个目标类型,比如Person——>PersonDto,User——>UserDto。
问:什么情况下使用AutoMapper?
答:一般在项目的开发中,经常需要将Entity实体映射成ModelDto或者ViewModel,这个时候,使用AutoMapper仅需要简单的配置,就可以实现这些需求,非常方便。
接下来,讲一下项目中的具体配置。
在我的ABP项目中,首先核心层有一个实体类TerminalDevices,类定义如下:

1 namespace Noah.ChargeStation.Core.Entities
2 {
3 //终端表
4 public class TerminalDevices : Entity
5 {
6
7 /// <summary>
8 /// 终端编码
9 /// </summary>
10 public virtual string Code
11 {
12 get;
13 set;
14 }
15 /// <summary>
16 /// IMEI
17 /// </summary>
18 public virtual string IMEI
19 {
20 get;
21 set;
22 }
23 /// <summary>
24 /// SIMCardNO
25 /// </summary>
26 public virtual string SIMCardNO
27 {
28 get;
29 set;
30 }
31 /// <summary>
32 /// InstallDate
33 /// </summary>
34 public virtual DateTime? InstallDate
35 {
36 get;
37 set;
38 }
39 /// <summary>
40 /// PlacePosition
41 /// </summary>
42 public virtual string PlacePosition
43 {
44 get;
45 set;
46 }
47 /// <summary>
48 /// Version
49 /// </summary>
50 public virtual int? Version
51 {
52 get;
53 set;
54 }
55 /// <summary>
56 /// TotalCoins
57 /// </summary>
58 public virtual int TotalCoins
59 {
60 get;
61 set;
62 }
63 /// <summary>
64 /// CurrentBoxCoins
65 /// </summary>
66 public virtual int CurrentBoxCoins
67 {
68 get;
69 set;
70 }
71 /// <summary>
72 /// 最小计费单位
73 /// </summary>
74 public virtual int MinimumUnit
75 {
76 get;
77 set;
78 }
79 /// <summary>
80 /// 充电时长
81 /// </summary>
82 public virtual int ChargeTime
83 {
84 get;
85 set;
86 }
87 /// <summary>
88 /// MoneyBoxCapacity
89 /// </summary>
90 public virtual int? MoneyBoxCapacity
91 {
92 get;
93 set;
94 }
95 /// <summary>
96 /// 终端名称
97 /// </summary>
98 public virtual string Name
99 {
100 get;
101 set;
102 }
103 /// <summary>
104 /// 终端类型:0--同城类终端 1--跨城类终端
105 /// </summary>
106 public virtual int? Type
107 {
108 get;
109 set;
110 }
111 /// <summary>
112 /// 所属城市
113 /// </summary>
114 public virtual int? CityID
115 {
116 get;
117 set;
118 }
119 /// <summary>
120 /// 所属运营商
121 /// </summary>
122 public virtual int? OperatorID
123 {
124 get;
125 set;
126 }
127 /// <summary>
128 /// 所属站台
129 /// </summary>
130 public virtual int? StationID
131 {
132 get;
133 set;
134 }
135 /// <summary>
136 /// 经度
137 /// </summary>
138 public virtual decimal? Longitude
139 {
140 get;
141 set;
142 }
143 /// <summary>
144 /// 纬度
145 /// </summary>
146 public virtual decimal? Latitude
147 {
148 get;
149 set;
150 }
151 /// <summary>
152 /// 支付宝二维码内容
153 /// </summary>
154 public virtual string AlipayEWMContent
155 {
156 get;
157 set;
158 }
159 /// <summary>
160 /// 支付宝二维码图片
161 /// </summary>
162 public virtual string AlipayEWMImage
163 {
164 get;
165 set;
166 }
167 /// <summary>
168 /// 微信二维码内容
169 /// </summary>
170 public virtual string WechatEWMContent
171 {
172 get;
173 set;
174 }
175 /// <summary>
176 /// 微信二维码图片
177 /// </summary>
178 public virtual string WechatEWMImage
179 {
180 get;
181 set;
182 }
183 /// <summary>
184 /// 正在充电数量
185 /// </summary>
186 public virtual int? ChargingNum
187 {
188 get;
189 set;
190 }
191 /// <summary>
192 /// 上次通讯时间
193 /// </summary>
194 public virtual DateTime? LastConnectTime
195 {
196 get;
197 set;
198 }
199 /// <summary>
200 /// 0--失联 1--正常 2--维修 3--维护4--下线
201 /// </summary>
202 public virtual int? Status
203 {
204 get;
205 set;
206 }
207 /// <summary>
208 /// SystemCode
209 /// </summary>
210 public virtual string SystemCode
211 {
212 get;
213 set;
214 }
215 /// <summary>
216 /// Certificate
217 /// </summary>
218 public virtual string Certificate
219 {
220 get;
221 set;
222 }
223 /// <summary>
224 /// 到期时间
225 /// </summary>
226 public virtual DateTime? DueDate
227 {
228 get;
229 set;
230 }
231 /// <summary>
232 /// 创建人
233 /// </summary>
234 public virtual string CreatedBy
235 {
236 get;
237 set;
238 }
239 /// <summary>
240 /// 创建日期
241 /// </summary>
242 public virtual DateTime? CreatedDate
243 {
244 get;
245 set;
246 }
247 /// <summary>
248 /// 最后更新人
249 /// </summary>
250 public virtual string UpdatedBy
251 {
252 get;
253 set;
254 }
255 /// <summary>
256 /// 最后更新日期
257 /// </summary>
258 public virtual DateTime? UpdatedDate
259 {
260 get;
261 set;
262 }
263 public TerminalDevices()
264 {
265
266 }
267
268 }
269
270 }
可以看到,仅一个实体类,就要将近300行的代码,但是在服务层或者展现层使用的时候,有些属性是不需要的,所以这时我们就要定义我们的Dto类了。
随后,我在ABP项目中的服务层定义了一个对应的TerminalDeviceDto类,定义如下:

1 namespace Noah.ChargeStation.Application.TerminalDevicesApp.Dto
2 {
3 public class TerminalDeviceDto:IDto
4 {
5 [DisplayName("设备编码")]
6 public string Code { get; set; }
7 public string IMEI { get; set; }
8 [DisplayName("SIM卡号")]
9 public string SIMCardNO { get; set; }
10 public string InstallDate { get; set; }
11 public string PlacePosition { get; set; }
12 public int Version { get; set; }
13 [DisplayName("总投币")]
14 public int TotalCoins { get; set; }
15 public int CurrentBoxCoins { get; set; }
16 public int MinimumUnit { get; set; }
17 public int ChargeTime { get; set; }
18 public int MoneyBoxCapacity { get; set; }
19 public string Name { get; set; }
20 public int Type { get; set; }
21 public int CityId { get; set; }
22 public int OperatorId { get; set; }
23 public int StationId { get; set; }
24 public decimal Longitude { get; set; }
25 public decimal Latitude { get; set; }
26 public string AlipayEWMContent { get; set; }
27 public string AlipayEWMImage { get; set; }
28 public string WechatEWMContent { get; set; }
29 public string WechatEWMImage { get; set; }
30 public int ChargingNum { get; set; }
31 public DateTime LastConnectTime { get; set; }
32 public int Status { get; set; }
33 public string SystemCode { get; set; }
34 public string Certificate { get; set; }
35 public DateTime DueDate { get; set; }
36 public string CreatedBy { get; set; }
37 public DateTime CreatedDate { get; set; }
38 public string UpdatedBy { get; set; }
39 public DateTime UpdatedDate { get; set; }
40
41 }
42 }
当然,这里的Dto类定义的属性跟你的具体业务相关,定义的属性还可能更少。
上面讲的是源类型和目标类型的定义,下面开始讲它们之间的映射配置。
首先,我在应用服务层新建一个文件夹取名“AutoMapper”,里面放跟AutoMapper配置相关的东西。
如图,新建一个类TerminalDeviceProfile(CityProfile类是我的另一个实体类对应的AutoMapper配置文件),定义如下:
namespace Noah.ChargeStation.Application.AutoMapper
{
public class CityProfile:Profile
{
protected override void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Cities, CityDto>();
});
}
}
}
如果您对这么配置不清楚原因,请查看我的AutoMapper系列教程,点击查看。
再创建一个AutoMapperWebConfig静态类,定义如下:
namespace Noah.ChargeStation.Application.AutoMapper
{
public static class AutoMapperWebConfig
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile<CityProfile>();
cfg.AddProfile<TerminalDeviceProfile>();
});
Mapper.AssertConfigurationIsValid();//验证所有的映射配置是否都正常
}
}
}
接下来,在应用服务层的模块类中调用该静态类的静态方法,加载所有的AutoMapper配置信息。
namespace Noah.ChargeStation.Application
{
[DependsOn(typeof(ChargeStationCoreModule), typeof(AbpAutoMapperModule))]
public class ChargeStationApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
AutoMapperWebConfig.Configure();//一次性加载所有映射配置
}
}
}
这里需要注意的是,AutoMapper的配置一般放在项目启动的时候进行加载且只加载一次就够了,而在ABP框架搭建的项目中,除了展现层(Web和WebAPI层),其他层都会有一个Module类(类名以Module结尾)。这些类都重写了父类AbpModule的Initialize方法,旨在模块初始化的时候调用,这样,映射的配置也在模块初始化的时候完成了。如果在一般的ASP.Net项目中,应该在全局配置文件Global.asax中的Application_Start方法中调用AutoMapper的配置方法,其他项目类似。
以后,想要添加配置信息时,只需要定义相应的XXProfile类,然后在AutoMapperWebConfig类中添加配置文件类就可以了。