我正在使用AutoMapper将Entity映射到ViewModel。该实体的一个属性是datetime。我想使用TimeZone将该日期时间转换为本地日期时间。 TimeZone存储在用户的会话对象中。我已经有ISessionManager
来回复用户会话中的信息。
我不知道如何将此ISessionManager注入AutoMapper
在下面的代码中,如何将ISessionManager.CurrentTimeZone
属性传递给FromUTCToLocal()方法?
public class SessionManager:ISessionManager
{
public TimeZoneInfo CurrentTimeZone
{
return (TimeZoneInfo)Session["CurrentTimeZone"];
}
}
public static class DateTimeExtenstions
{
public static DateTime FromLocalToUTC(this DateTime dateTime, TimeZoneInfo timeZone)
{
// Here instead of taking timeZone as parameter i can
// use servicelocator to get instance of ISessionManager
// like var timeZone = ServiceLocator.GetInstance<ISessionManager>()
// However i don't want to use servicelocator pattern since
// everywhere else i am using IOC
// also it doesnt make sense to use ServiceLocator inside extension method
return TimeZoneInfo.ConvertTimeToUtc(dateTime, timeZone);
}
}
public class AutoMapperConfig
{
public static IMapper Config()
{
var config = new MapperConfiguration(cfg =>
{
//Create all maps here
cfg.CreateMap<MyEntity, MyViewModel>()
.ForMember(vm => vm.CreatedDateTime,
y => y.MapFrom(entity => entity.CreatedOn.FromUTCToLocal()))
});
return config.CreateMapper();
}
}
public static class UnityConfig
{
public static void RegisterComponents(IMapper mapper)
{
var container = new UnityContainer();
container.RegisterType<ISessionManager, SessionManager>(new HierarchicalLifetimeManager());
container.RegisterInstance(mapper);
UnityServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents(AutoMapperConfig.Config());
}
}
答案 0 :(得分:4)
我认为这是一种反模式,因为地图选手应该是愚蠢的,因此你可能想要抵制在其中加入过多逻辑的诱惑。查询数据是您的域实现的责任,但是如果您在没有它的情况下进行管理(特别是不在扩展方法中),那么您就不使用ServiceLocator了。
也许你应该丰富你要映射的域对象,而不是在映射过程中尝试添加缺失的信息(TimeZoneInfo)。
答案 1 :(得分:0)
AutoMapper实际上并不是一个反模式,它实际上是为了准确处理你想要的东西,你只需要采取不同的方法(奇怪的是我解决了这个问题,同时也处理了一个UTC问题,其中我最初也是尝试了一种基于扩展方法的解决方案。)
您可以使用AutoMapper的ValueResolvers而不是使用扩展方法。根据这是否是特定于某个特定类的映射,或者它是某个特定数据类型的一般映射,您需要实现IValueResolver(对于前者)或IMemberValueResolver(对于后者)。
这是一个很好的资源,可以帮助你完成大部分工作: https://github.com/AutoMapper/AutoMapper/wiki/Custom-value-resolvers
没有解决的问题是注入旋转变压器。
一个例子是这样的:
public class DateTimeUtcResolver : IMemberValueResolver<object, object, DateTime, DateTime>
{
ISessionManager sessionManager;
public DateTimeUtcResolver(ISessionManager sessionManager)
{
this.sessionManager = sessionManager;
}
public DateTime Resolve(object source, object destination, DateTime sourceMember, DateTime destinationMember, ResolutionContext context)
{
//logic
}
}
你的映射器会有这样的东西:
cfg.CreateMap<MyEntity, MyViewModel>()
.ForMember(vm => vm.CreatedDateTime,
y => y.ResolveUsing<DateTimeUtcResolver, DateTime>(entity => entity.CreatedOn))
从那里只记得用AutoMapper注册你的IOC容器,这样就可以确定ISessionManager的实现。这本身可能很棘手,但取决于你正在使用什么类型的容器(这个帮助了我很多,ymmv:Automapper and request specific resources)