Разрешение HttpControllerContext с помощью Castle Windsor

В веб-API ASP.NETэкземпляры HttpControllerContext предоставляют много информации о текущей среде, включая URI текущего запроса.

Если служба полагается на на такую ​​информацию (например, URI запроса), должна быть возможность ввести эту информацию в службу.

Это довольно легко сделать с помощью DI Poor Man: просто реализуйте собственный IHttpControllerActivator.

Однако с замком Виндзор это внезапно становится очень трудным.Ранее я описал очень запутанный способрешения этой проблемы, но он зависит от образа жизни PerWebRequest, и оказывается, что этот образ жизни не работает в сценариях самостоятельного хостинга, потому что HttpContext.Current пусто.

До сих пор мне удавалось заставить это работать, передавая нужную информацию в качестве встроенного аргумента в метод Resolve из пользовательского IHttpControllerActivator:

public IHttpController Create(
    HttpControllerContext controllerContext,
    Type controllerType)
{
    var baseUri = new Uri(
        controllerContext
            .Request
            .RequestUri
            .GetLeftPart(UriPartial.Authority));

    return (IHttpController)this.container.Resolve(
        controllerType,
        new { baseUri = baseUri });
}

Однако по умолчанию это работает, только если немедленно запрошенный тип полагается на на аргумент (т.е. если сам запрошенный контроллер зависит от baseUri). Если зависимость от baseUriскрыта глубже в иерархии зависимостей, она не работает по умолчанию, поскольку встроенные аргументы не распространяются на более глубокие уровни.

Это поведение можно изменить с помощью пользовательского IDependencyResolver (IDependencyResolver Castle Windsor, а не IDependencyResolver веб-API ASP.NET):

public class InlineDependenciesPropagatingDependencyResolver :
    DefaultDependencyResolver
{
    protected override CreationContext RebuildContextForParameter(
        CreationContext current, Type parameterType)
    {
        if (parameterType.ContainsGenericParameters)
        {
            return current;
        }

        return new CreationContext(parameterType, current, true);
    }
}

Обратите внимание, что trueпередается как propagateInlineDependenciesаргумент конструктора вместо false, который является реализацией по умолчанию.

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

this.container = 
    new WindsorContainer(
        new DefaultKernel(
            new InlineDependenciesPropagatingDependencyResolver(),
            new DefaultProxyFactory()),
        new DefaultComponentInstaller());

Мне интересно, это лучшее решение этой проблемы или есть лучший/более простой способ?

27
задан Mark Seemann 1 June 2012 в 17:17
поделиться