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

时间:2013-04-02 14:15:58

标签: c# automapper automapper-2

我目前正在评估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<string, string> Links { get; set; }
}

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

public IEnumerable<CustomerResource> Get()
{
    Func<Customer, CustomerResource> map = customer => 
        new CustomerResource
        {
            Name = customer.Name,
            Links = new Dictionary<string, string>()
            {
                {"self", Url.Link("DefaultApi", new { controller = "Customers", name = customer.Name })}
            }
        }

    var customers = Repository.GetAll();
    return customers.Select(map);
}

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

你如何解决这个难题?

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

2 个答案:

答案 0 :(得分:2)

我会考虑使用Custom Type Converter。类型转换器可以具有通过IOC容器注入的上下文信息。或者,由于转换器在配置时实例化,因此它可以引用工厂,每次运行类型转换器时都会返回上下文信息。

简单示例

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

public interface IContextFactory
{
    HttpContext GetContext();
}

实施简单:

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

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

访问网址属性

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实例。

答案 1 :(得分:2)

这不是一个漂亮的解决方案,但在阅读完文档后,似乎没有一个...我们目前正在通过将Tuple<TDomainType, TContextStuff>映射到TDataTransfer来投入上下文内容。所以在你的情况下,你Mapper.CreateMap<Tuple<Customer, Controller>, CustomerResource>

不漂亮,但确实有效。