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?