2013-04-02 67 views
7

我目前正在評估AutoMapper是否對我們的項目有利。我正在使用ASP.NET Web API處理RESTful Web API,並且我必須返回的其中一個內容是包含鏈接的資源。考慮這個簡單的例子,使用下面的域對象:在AutoMapper中使用上下文值的投影

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中失敗。

+0

目前我傾向於在呼叫地點創建地圖,但我不知道這是個好主意。 –

+0

何時定義鏈接?在運行期間? – carlpett

+0

更確切地說,是在編譯時,1)在啓動時或3)映射/解析時定義的鏈接? – carlpett

回答

2

我會着手使用Custom Type Converter。類型轉換器可以通過IOC容器注入上下文信息。或者,由於轉換器在配置時被實例化,所以它可以具有對每次運行類型轉換器時都會返回上下文信息的工廠的引用。

簡單的例子

你可以定義一個接口讓你的當前的「上下文」(這意味着什麼取決於你在做什麼,如何實現這樣的事情在這個例子中我就當前HttpContext的它獲取到會話,服務器,郵件,訪問等...):

public interface IContextFactory 
{ 
    HttpContext GetContext(); 
} 

和實現很簡單:

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

您的自定義類型轉換器可以從IOC容器中獲取IContextFactory的實例,並且每次運行映射時都可以調用GetContext()獲取當前請求的上下文。

訪問URL屬性

的UrlHelper來自附加到當前的控制器的情況下請求對象。不幸的是,這在HttpContext中不可用。但是,您可以覆蓋ApiController上的Initialize方法,並將controllerContext存儲在HttpContext中。項目集合:

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實例類型映射器。

+0

您如何獲得IoC背景?假設你正在MVC控制器中執行'Mapper.Map'。你將如何將執行的實例注入到解析器/轉換器中? – carlpett

+0

@carlpett,我更新了一個通過工廠抓取當前的Http上下文。 – PatrickSteele

+0

但是解析時HttpContext並不是我所需要的。 –

2

這不是一個漂亮的解決方案,但通過閱讀文檔後,似乎沒有一個......我們目前通過將Tuple<TDomainType, TContextStuff>映射到TDataTransfer來投放上下文。所以你的情況下,你會Mapper.CreateMap<Tuple<Customer, Controller>, CustomerResource>

不漂亮,但它的作品。

+0

這並不漂亮,但很有創意。我正在考慮嘗試這一點,但我已經在考慮配置嵌套映射時會產生的混亂。 –