ASP Web Api - IoC - Rozpoznaj HttpRequestMessage

Próbuję skonfigurować Castle Windsor z ASP.NET WebAPI.

Używam także pakietu Hyprlinkr (https://github.com/ploeh/Hyprlinkr) i dlatego potrzebuję instancji HttpRequestMessage wprowadzonej do jednej z zależności mojego kontrolera.

Śledzę ten artykuł Marka Seemanna -http://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspx , ale odkrywam, że chociaż API działa, kiedy dzwonię do niego, żądanie się zawiesza. Brak komunikatu o błędzie. To tak, jakby było w nieskończonej pętli. Zadzwoń do Resolve w moim Custom ControllerActivator

Myślę, że niektóre z moich rejestracji w Zamku są nieprawidłowe. Jeśli usunę te wymienione w powyższym artykule, mogę pomyślnie nawiązać połączenie z interfejsem API (aczkolwiek bez zależności, które wymagają rozwiązania)

Jakieś pomysły?

Kod jest poniżej

//Global.asax
public class WebApiApplication : HttpApplication
{
    private readonly IWindsorContainer container;

    public WebApiApplication()
    {
        container = 
            new WindsorContainer(
                new DefaultKernel(
                    new InlineDependenciesPropagatingDependencyResolver(), 
                    new DefaultProxyFactory()), 
                new DefaultComponentInstaller());

        container.Install(new DependencyInstaller());
    }

    protected void Application_Start()
    {        
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorCompositionRoot(this.container));
    }

// installer
public class DependencyInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<TypedFactoryFacility>();

        container.Register(
            Component.For<ValuesController>()
                .Named("ValuesController")
                .LifeStyle.PerWebRequest,

            Component.For<IResourceLinker>()
                .ImplementedBy<RouteLinker>()
                .LifeStyle.PerWebRequest,

            Component.For<IResourceModelBuilder>()
                .ImplementedBy<ResourceModelBuilder>()
                .LifeStyle.PerWebRequest,

                Component.For<HttpRequestMessage>()
                .Named("HttpRequestMessage")
                .LifeStyle.PerWebRequest
            );
    }
}

//Activator

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorCompositionRoot(IWindsorContainer container)
    {
        this.container = container;
    }

    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType)
    {
        var controller = (IHttpController)this.container.Resolve(controllerType, new { request = request });

        request.RegisterForDispose(
            new Release(
                () => this.container.Release(controller)));

        return controller;
    }

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

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

EDYCJA *********** INFORMACJE DODATKOWE ****************

Ustawiłem więc scenariusz, w którym kontroler po prostu pobiera HttpRequestMessage jako argument ctor i znalazł:

To działa:

//controller
public class ValuesController : ApiController
    {
        private readonly HttpRequestMessage _httpReq;

        public ValuesController(HttpRequestMessage httpReq)
        {
            _httpReq = httpReq;
        }
//IHttpControllerActivator
public IHttpController Create(
            HttpRequestMessage httpRequest,
            HttpControllerDescriptor controllerDescriptor,
            Type controllerType)
        {

            var controller = (IHttpController)this.container.Resolve(
                controllerType, new { httpReq = httpRequest });

            return controller;

Jednak tak się nie dzieje.

//controller
public class ValuesController : ApiController
    {
        private readonly HttpRequestMessage _httpReq;

        public ValuesController(HttpRequestMessage request)
        {
            _httpReq = request;
        }

//IHttpControllerActivator
public IHttpController Create(
            HttpRequestMessage request,
            HttpControllerDescriptor controllerDescriptor,
            Type controllerType)
        {

            var controller = (IHttpController)this.container.Resolve(
                controllerType, new { request = request });

            return controller;

tj. gdy obiekt anon ma właściwość o nazwie „request”, a argument kontrolera ctor nazywa się „request”. To w jakiś sposób sprawia, że ​​kontroler uważa, że ​​właściwość żądania ma wartość NULL. Co powoduje błąd, który widzę:

Nie można ponownie użyć instancji „ApiController”. „ApiController” musi być skonstruowany dla każdej przychodzącej wiadomości. Sprawdź swój niestandardowy „IHttpControllerActivator” i upewnij się, że nie będzie produkował tej samej instancji.

w System.Web.Http.ApiController.ExecuteAsync (HttpControllerContext controllerContext, CancellationToken cancellationToken) w System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal (żądanie HttpRequestMessage, CancellationToken cancellationToken) w System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync (HttpRequestMessage żądanie, Token anulowania anulowania tokenu)

przeczytaj toJak mogę wzbogacić kompozycję obiektu w StructureMap bez wywoływania wtrysku Settera?

Wyjaśnia podobny scenariusz.

Oczywiście, hyprlinkr ma swój argument ctor dla HttpRequestMessage o nazwie „request”, więc muszę określić obiekt anon tą nazwą właściwości.

Jakieś pomysły?

questionAnswers(2)

yourAnswerToTheQuestion