C# 如何将服务注入AutoMapper?

C# 如何将服务注入AutoMapper?,c#,asp.net-mvc,unity3d,automapper,inversion-of-control,C#,Asp.net Mvc,Unity3d,Automapper,Inversion Of Control,我使用AutoMapper将实体映射到ViewModel。实体的属性之一是datetime。我想使用时区将datetime转换为本地datetime。时区存储在用户的会话对象中。我已经有了ISessionManager,它可以从用户会话中检索信息。 我不知道如何将此ISessionManager注入AutoMapper 在下面的代码中,如何将ISessionManager.CurrentTimeZone属性传递到FromUTCToLocal()方法中 公共类会话管理器:ISessionManag

我使用AutoMapper将实体映射到ViewModel。实体的属性之一是datetime。我想使用时区将datetime转换为本地datetime。时区存储在用户的会话对象中。我已经有了
ISessionManager
,它可以从用户会话中检索信息。 我不知道如何将此ISessionManager注入AutoMapper

在下面的代码中,如何将
ISessionManager.CurrentTimeZone
属性传递到FromUTCToLocal()方法中

公共类会话管理器:ISessionManager
{
公共时区信息当前时区
{
返回(时区信息)会话[“当前时区”];
}
}
公共静态类DateTimeExtensions
{
来自LocalToutc的公共静态日期时间(此日期时间日期时间,时区信息时区)
{
//在这里,我可以不使用时区作为参数
//使用servicelocator获取ISessionManager的实例
//比如var timeZone=ServiceLocator.GetInstance()
//但是我不想使用servicelocator模式,因为
//其他地方我都在使用IOC
//此外,在扩展方法中使用ServiceLocator也没有意义
返回TimeZoneInfo.ConvertTimeToUtc(日期时间,时区);
}        
}
公共类自动映射配置
{
公共静态IMapper配置()
{
var config=new-MapperConfiguration(cfg=>
{
//在此处创建所有地图
cfg.CreateMap()
.ForMember(vm=>vm.CreatedDateTime,
y=>y.MapFrom(entity=>entity.CreatedOn.FromUTCToLocal())
});
返回config.CreateMapper();
}
}   
公共静态类UnityConfig
{
公共静态无效注册表组件(IMapper映射器)
{
var container=new UnityContainer();
RegisterType(新的层次结构CallifetimeManager());
容器注册器状态(映射器);
UnityServiceLocator定位器=新的UnityServiceLocator(容器);
ServiceLocator.SetLocatorProvider(()=>locator);
}
}
公共类MVC应用程序:System.Web.HttpApplication
{
受保护的无效应用程序\u Start()
{
RegisterAllAreas();
UnityConfig.RegisterComponents(AutoMapperConfig.Config());
}
}

我认为这是一种反模式,因为映射程序被认为是愚蠢的,因此您可能希望抵制在其内部添加太多逻辑的诱惑。查询数据是域实现的责任,但是如果您到目前为止还没有使用ServiceLocator(特别是在扩展方法中没有使用ServiceLocator)进行管理,那么不使用ServiceLocator是正确的


也许你应该丰富你正在映射的域对象,而不是在映射过程中尝试添加缺少的信息(TimeZoneInfo)。

AutoMapper并不是一个反模式,它实际上是为处理你想要的内容而设计的,你只需要采取一种不同的方法(奇怪的是,我在处理UTC问题时解决了这个问题,在这个问题中,我最初也尝试了基于扩展方法的解决方案)

您需要的不是使用扩展方法,而是使用AutoMapper的ValueResolver。根据这是特定于特定类的映射还是特定数据类型的常规映射,您需要实现IValueResolver(前者)或IMemberValueResolver(后者)

这是一个很好的资源,可以帮助您实现目标:

没有解决的是注入到解析器中

例如:

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))
公共类DateTimeUtcResolver:IMemberValueResolver
{
ISessionManager会话管理器;
public DateTimeUtcResolver(ISessionManager会话管理器)
{
this.sessionManager=sessionManager;
}
公共日期时间解析(对象源、对象目标、日期时间源成员、日期时间目标成员、解析上下文)
{
//逻辑
}
}
然后,您的映射器将具有如下内容:

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))
cfg.CreateMap()
.ForMember(vm=>vm.CreatedDateTime,
y=>y.ResolveUsing(entity=>entity.CreatedOn))

从这里开始,请记住向AutoMapper注册您的IOC容器,以便确定ISessionManager的实现。这本身可能很棘手,但取决于您使用的容器类型(这个容器对我帮助很大,ymmv:)

我同意。这是一种反模式。