AutoMapper與ASP.NET MVC結合,一般會在Controller的Action中使用AutoMapper把前台傳遞過來的Presentation Model轉換成相應的業務邏輯上的Entity Model.如果在Action中寫AutoMapper.CreateMap<T1,T2>,這些代碼未免與業務邏輯無多大關系,所以不應該寫在Action中。我們可以利用ASP.NET MVC中的Filter這個特點,以過濾器的方式在執行Action中AutoMapper的轉換前就完成配置。
首先,要定義一個MyProfile, 繼承自AutoMapper的Profile類,並且重寫Configure()方法,在這個方法中進行配置。
[csharp]
public class OrderDomainMvcProfile : Profile
{
public override string ProfileName
{
get { return "OrderDomainMvcProfile"; }
}
protected override void Configure()
{
// Map……
Mapper.CreateMap<T1, T2>().ForMember(……);
}
}
public class OrderDomainMvcProfile : Profile
{
public override string ProfileName
{
get { return "OrderDomainMvcProfile"; }
}
protected override void Configure()
{
// Map……
Mapper.CreateMap<T1, T2>().ForMember(……);
}
}然後再Filter中進行加載
[csharp]
[AttributeUsageAttribute(AttributeTargets.Class |AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class AutoMapperConfigurationActionFilterAttribute : FilterAttribute
{
public AutoMapperConfigurationActionFilterAttribute(Type profileType)
{
Mapper.Configuration.AddProfileThreadSafe(Activator.CreateInstance(profileType) as Profile);
}
}
[AttributeUsageAttribute(AttributeTargets.Class |AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class AutoMapperConfigurationActionFilterAttribute : FilterAttribute
{
public AutoMapperConfigurationActionFilterAttribute(Type profileType)
{
Mapper.Configuration.AddProfileThreadSafe(Activator.CreateInstance(profileType) as Profile);
}
}最後把Filter應用到Controller的Action
[csharp]
[AutoMapperConfigurationActionFilter(typeof(OrderDomainMvcProfile))]
public virtual ActionResult OrderGrid_Select(GridCommand command)
{ ……
}
[AutoMapperConfigurationActionFilter(typeof(OrderDomainMvcProfile))]
public virtual ActionResult OrderGrid_Select(GridCommand command)
{ ……
}
這裡介紹另外一種比較特別的方法。我希望在程序剛剛開始啟動,即Application_Start的時候,就完成所有的配置,一勞永逸。如果ASP.NET MVC有多個Domain對應多個Area,那麼在global.asax.cs中Application_Start中就要寫很多配置AutoMapper的代碼。這裡我們使用反射,去尋找DLL中實現了IStartupTask的接口的方法,然後運行Excecute方法即可。
創建一個IStartupTask接口
[csharp]
public interface IStartupTask
{
void Execute();
}
public interface IStartupTask
{
void Execute();
}實現這個接口
[csharp]
public class AutoMapperStartupTask : IStartupTask
{
public void Execute()
{
Create<User, UserModel>();
Create<Widget, WidgetModel>();
Create<WidgetDefinition, WidgetDefinitionModel>();
//Mapper.CreateMap<ModuleDefinition, ModuleDefinitionModel>()
// .ForMember(m => m.AppId, o => o.MapFrom(e => e.App == null ? (int?)null : e.App.Id))
// .ForMember(m => m.AppTitle, o => o.MapFrom(e => e.App == null ? null : e.App.Title));
//Mapper.CreateMap<ModuleDefinitionModel, ModuleDefinition>();
}
protected virtual void Create<T1, T2>()
{
Mapper.CreateMap<T1, T2>();
Mapper.CreateMap<T2, T1>();
}
}
public class AutoMapperStartupTask : IStartupTask
{
public void Execute()
{
Create<User, UserModel>();
Create<Widget, WidgetModel>();
Create<WidgetDefinition, WidgetDefinitionModel>();
//Mapper.CreateMap<ModuleDefinition, ModuleDefinitionModel>()
// .ForMember(m => m.AppId, o => o.MapFrom(e => e.App == null ? (int?)null : e.App.Id))
// .ForMember(m => m.AppTitle, o => o.MapFrom(e => e.App == null ? null : e.App.Title));
//Mapper.CreateMap<ModuleDefinitionModel, ModuleDefinition>();
}
protected virtual void Create<T1, T2>()
{
Mapper.CreateMap<T1, T2>();
Mapper.CreateMap<T2, T1>();
}
}
在Global.ascx中一次性引入所有的AutoMapper配置
[csharp]
protected void Application_Start()
{
……
ExecuteStartupTasks();
}
private void ExecuteStartupTasks()
{
List<IStartupTask> startupTasks = new List<IStartupTask>();
Assembly asm = this.ExecutingAssembly;
// get path of executing (bin) folder from the current executing assembly
string codeBase = this.ExecutingAssembly.CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
string bin = Path.GetDirectoryName(path);
string[] assemblies = Directory.GetFiles(bin, "*.dll");
foreach (String file in assemblies)
{
try
{
if (File.Exists(file))
{
// load the assembly
asm = Assembly.LoadFrom(file);
// get all types from the assembly that inherit IStartupTask
var query = from t in asm.GetTypes()
where t.IsClass && t.GetInterface(typeof(IStartupTask).FullName) != null
select t;
// add types to list of startup tasks
foreach (Type type in query)
{
startupTasks.Add((IStartupTask)Activator.CreateInstance(type));
}
}
}
catch (Exception ex)
{
Exceptions.LogException(ex);
}
}
// execute each startup task
foreach (IStartupTask task in startupTasks)
{
task.Execute();
}
}