Существует ли HttpControllerBuilder для веб-API ASP.NET?

Если я хочу реализовать Injection Dependency для ASP.NET MVC-контроллеров, я могу использовать интерфейс IControllerFactory для создания класса factory, а затем зарегистрировать его в Global.asax.cs, например:

ControllerBuilder.Current.SetControllerFactory(controllerFactory)

(ссылка: http://www.dotnetcurry.com/ShowArticle.aspx?ID=786)

Теперь мой вопрос:

Как я могу установить factory для производного класса IHttpControllerActivator?

У нас есть что-то в ASP.NET MVC 4.0, например:

HttpControllerBuilder.Current.SetApiControllerActivator(httpControllerActivator)


Update:

Я хочу добавить свой текущий код, может быть полезно разобраться в этом случае:

Мой настраиваемый HttpControllerActivator:

public class MyCustomApiActivator : DefaultHttpControllerActivator 
                                    //or IHttpControllerActivator ?
{
    private readonly Dictionary<string, Func<HttpRequestMessage, IHttpController>> _apiMap;

    public MyCustomApiActivator(IMyRepository repository)
    {
        if (repository == null)
        {
            throw new ArgumentException("repository");
        }
        _apiMap = new Dictionary<string, Func<HttpRequestMessage, IHttpController>>();
        controllerMap["Home"] = context => new HomeController();
        _apiMap["MyCustomApi"] = context => new MyCustomApiController(repository);
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        if(_apiMap.ContainsKey(controllerType.Name))
            return _apiMap[controllerType.Name](request);
        return null;
    }
}

Мой составной корень:

public class CompositionRoot
{
    private readonly IHttpControllerActivator _apiControllerActivator;

    public CompositionRoot()
    {
        _apiControllerActivator = CompositionRoot.CreateHttpControllerActivator();
    }

    public IHttpControllerActivator ApiControllerActivator
    {
        get { return _apiControllerActivator; }
    }

    private static IHttpControllerActivator CreateHttpControllerActivator()
    {
        string defaultRepositoryTypeName = ConfigurationManager.AppSettings["DefaultRepositoryTypeName"];
        var defaultRepositoryType = Type.GetType(defaultRepositoryTypeName, true);
        var defaultRepository = (IMyRepository)Activator.CreateInstance(defaultRepositoryType);

        var apiController = new MyCustomApiActivator(defaultRepository);
        return apiController;
    }
}

Наконец, это внутри моего Global.asax.cs, где мне нужен трюк:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);


        var root = new CompositionRoot();
        //The following line raise this compile-time error:
        // cannot convert from 'System.Web.Http.Dispatcher.IHttpControllerActivator' 
        //                to 'System.Web.Mvc.IControllerFactory'
        ControllerBuilder.Current.SetControllerFactory(root.ApiControllerActivator);
    }

Ответ 1

Марк Семанн, автор Injection Dependency в .NET, имеет короткую серию на DI с ASP.NET WebAPI.

Он помещает корень композиции внутри IHttpControllerActivator

Может быть, это помогает.


Обновление

GlobalConfiguration.Configuration.Services.Replace(
  typeof(IHttpControllerActivator),
  new PoorMansCompositionRoot());

Регистрирует ваш пользовательский HttpControllerActivator глобально.

Ответ 2

В ASP.NET Web API HttpControllerDispatcher отвечает за построение контроллеров. Он работает с DependecyResolver по умолчанию, но если вы хотите расширить его функциональность, вам необходимо переопределить его метод SendAsync и зарегистрировать его снова.

Пример:

public class MyCustomDispatcher : HttpControllerDispatcher {

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, 
        CancellationToken cancellationToken) {

        // Do your stuff here

        // According to your requirements, either run its default functionality 
        // or return your own stuff
        return base.SendAsync(request, cancellationToken);
    }
}

Примечание:

Однако мне не удалось найти элегантный способ заменить стандартный во всем мире. Вы можете легко заменить по умолчанию один на маршрут прикрепление этого настраиваемого диспетчера к маршруту, но, похоже, нет способ сделать это глобально. Я открыл дискуссию об этом на сайт проекта: http://aspnetwebstack.codeplex.com/discussions/400366