2

我使用Drum它提供了一個通用類`UriMaker:如何使用Simple Injector註冊Drum.UriMaker <>?

public class UriMaker<TController> 
{ 
    // I need use this one 
    public UriMaker(UriMakerContext context, HttpRequestMessage request) { } 

    public UriMaker(Func<MethodInfo, RouteEntry> mapper, UrlHelper urlHelper) { } 
} 

像這樣來使用:

public class UserController : ApiController 
{ 
    public UserController(UriMaker<UserController> urlMaker) {} 
} 

我已經使用統一進行註冊:

container.RegisterType(typeof(UriMaker<>), 
    new InjectionConstructor(typeof(UriMakerContext), typeof(HttpRequestMessage))); 

但現在正在遷移到Simple Injector。我已經有這個了:

UriMakerContext uriMaker = config.MapHttpAttributeRoutesAndUseUriMaker(); 
container.RegisterSingle(uriMakerContext); 

那麼現在如何註冊UriMaker<>本身?

回答

2

雖然可以配置簡單的噴油器,允許直接注入UriMaker<TController>到您的控制器,我對這種強烈建議出於多種原因。

首先,你應該努力減少您的應用程序需要外部庫的依賴關係。這可以通過定義特定於應用程序的抽象(符合ISP)輕鬆完成。

其次,直接注入UriMaker使您非常難以測試,因爲UriMaker被拉入您的測試代碼中,同時它假定活動的HTTP請求並假定Web API路由系統配置正確。這些都是你不希望你的測試代碼依賴的東西。

最後,它使verifying the object graph更難,因爲UriMaker取決於HttpRequestMessage,這是一個運行時的值。通常,運行時值不應該注入到服務的構造函數中。您應該使用組件(包含應用程序行爲的東西)構建對象圖,並在構建之後通過對象圖發送運行時數據。

所以不是,我建議以下抽象:

public interface IUrlProvider 
{ 
    Uri UriFor<TController>(Expression<Action<TController>> action); 
} 

現在你的控制器可以依賴的,而不是依賴於外部庫這個IUrlProvider

public class UserController : ApiController 
{ 
    private readonly IUrlProvider urlProvider; 

    public UserController(IUrlProvider urlProvider) 
    { 
     this.urlProvider = urlProvider; 
    } 

    public string Get() 
    { 
     this.urlProvider.UriFor<HomeController>(c => c.SomeFancyAction()); 
    } 
} 

在幕後,你當然還需要調用Drum,爲此你需要定義IUrlProvider代理執行:

public class DrumUrlProvider : IUrlProvider 
{ 
    private readonly UriMakerContext context; 
    private readonly Func<HttpRequestMessage> messageProvider; 

    public DrumUrlProvider(UriMakerContext context, 
     Func<HttpRequestMessage> messageProvider) 
    { 
     this.context = context; 
     this.messageProvider= messageProvider; 
    } 

    public Uri UriFor<TController>(Expression<Action<TController>> action) 
    { 
     HttpRequestMessage message = this.messageProvider.Invoke(); 
     var maker = new UriMaker<TController>(this.context, message); 
     return maker.UriFor(action); 
    } 
} 

此實現可以通過以下方式註冊爲單:

container.EnableHttpRequestMessageTracking(config); 

UriMakerContext uriMakerContext = 
    config.MapHttpAttributeRoutesAndUseUriMaker(); 

IUrlProvider drumProvider = new DrumUrlProvider(uriMakerContext, 
    () => container.GetCurrentHttpRequestMessage()); 

container.RegisterSingle<IUrlProvider>(drumProvider); 

此示例使用Simple Injector Web API integration package,使檢索當前請求的HttpRequestMessage使用EnableHttpRequestMessageTrackingGetCurrentHttpRequestMessage擴展方法作爲解釋here

+1

這真是太棒了,謝謝!同時我找到了這個解決方案:http://pastebin.com/LhidzEVF。我更喜歡你,因爲它至少涉及更少的新課程。並有助於避免直接注入外部組件。 – abatishchev 2014-10-30 22:59:51

+0

@abatishchev:是的,你的解決方案是我在第一行的答案中勸阻的解決方案:-) – Steven 2014-10-30 23:13:55

+0

是的,確切地說,謝謝你的推理:) – abatishchev 2014-10-31 00:04:57

相關問題