2

Я использую Drum, который обеспечивает общий класс `UriMaker:Как зарегистрировать 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) {} 
} 

Я использовал, чтобы зарегистрировать его с Unity:

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-запрос и предполагает правильную настройку системы маршрутов веб-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, используя методы расширения текущего запроса в EnableHttpRequestMessageTracking и GetCurrentHttpRequestMessage как объяснено here.

+1

Это просто великолепно, спасибо! Тем временем я нашел это решение: http://pastebin.com/LhidzEVF. Мне нравится ваше больше, потому что он включает как минимум новые классы. И помогает избежать непосредственного впрыскивания внешнего компонента. – abatishchev

+0

@abatishchev: Да, ваше решение - это решение, которое я отговариваю в своем ответе на первой строке :-) – Steven

+0

Да, точно, спасибо за рассуждение :) – abatishchev

Смежные вопросы