使用AutoMapper中的上下文值进行投影

我目前正在评估AutoMapper是否对我们的项目有益。 我正在使用ASP.NET Web API开发RESTful Web API,我必须返回的一个内容是包含链接的资源。 考虑这个简化的示例,使用以下域对象:

public class Customer { public string Name { get; set; } } 

我需要将它映射到一个资源对象,有点像DTO,但增加了属性以方便REST。 这是我的资源对象可能是这样的:

 public class CustomerResource { public string Name { get; set; } public Dictionary Links { get; set; } } 

Links属性需要包含相关资源的链接。 现在,我可以使用以下方法构建它们:

 public IEnumerable Get() { Func map = customer => new CustomerResource { Name = customer.Name, Links = new Dictionary() { {"self", Url.Link("DefaultApi", new { controller = "Customers", name = customer.Name })} } } var customers = Repository.GetAll(); return customers.Select(map); } 

…但这非常繁琐,我有很多嵌套资源等等。 我看到的问题是我无法使用AutoMapper,因为它不允许我在投影期间提供某些事物,这些事物的范围限定为执行映射操作的点。 在这种情况下,ApiController的Url属性提供了为我创建链接所需的UrlHelper实例,但可能还有其他情况。

你会如何解决这个难题?

PS我专门针对这个问题键入了这段代码,它在你的头脑中编译但在你喜欢的IDE中可能会失败。

这不是一个很好的解决方案,但在阅读了文档后,似乎没有一个…我们目前通过将Tuple映射到TDataTransfer来抛出上下文的东西。 所以在你的情况下你是Mapper.CreateMap, CustomerResource>

不漂亮,但它的工作原理。

我会查看使用自定义类型转换器 。 类型转换器可以具有通过IOC容器注入的上下文信息。 或者,由于转换器在配置时被实例化,因此它可以引用工厂,该工厂每次运行类型转换器时都将返回上下文信息。

简单的例子

您可以定义一个接口来获取当前的“上下文”(这意味着取决于您正在做什么以及如何实现这些内容,因此对于此示例,我将只使用当前的HttpContext来访问Session,Server,Items,等等…):

 public interface IContextFactory { HttpContext GetContext(); } 

实施简单:

 public class WebContextFactory : IContextFactory { public HttpContext GetContext() { return HttpContext.Current; } } 

您的自定义类型转换器可以从IOC容器中获取IContextFactory的实例,并且每次运行映射时,您都可以调用GetContext()来获取当前请求的上下文。

访问Url属性

UrlHelper来自附加到当前控制器上下文的Request对象。 不幸的是,这在HttpContext中不可用。 但是,您可以覆盖ApiController上的Initialize方法并将controllerContext存储在HttpContext.Items集合中:

 protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext) { HttpContext.Current.Items["controllerContext"] = controllerContext; base.Initialize(controllerContext); } 

然后,您可以从当前的HttpContext访问它:

 var helper = ((HttpControllerContext) HttpContext.Current.Items["controllerContext"]).Request.GetUrlHelper(); 

我不确定它是最好的解决方案,但它可以在自定义类型映射器中获取UrlHelper实例。