gpt4 book ai didi

c# - ASP Web Api - IoC - 解析 HttpRequestMessage

转载 作者:可可西里 更新时间:2023-11-01 09:06:23 25 4
gpt4 key购买 nike

我正在尝试使用 ASP.NET WebAPI 设置 CaSTLe Windsor。

我也在使用 Hyprlinkr 包 ( https://github.com/ploeh/Hyprlinkr ),因此需要将 HttpRequestMessage 实例注入(inject)到我的 Controller 的依赖项之一中。

我正在关注 Mark Seemann 的这篇文章 - http://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspx ,但我发现虽然 API 运行,但当我调用它时,请求只是挂起。没有错误信息。就好像它在一个无限循环中。它卡在我的自定义 ControllerActivator 中对 Resolve 的调用上

我想我的一些 CaSTLe 注册有误。如果我删除上面文章中提到的那些,那么我可以成功调用 API(尽管没有我需要解决的依赖项)

有什么想法吗?

代码如下

//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);
}
}

编辑***********附加信息******************

所以我设置了一个场景,其中 Controller 只将 HttpRequestMessage 作为 ctor 参数并找到:

这个有效:

//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;

然而,这不是。

//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;

即当 anon 对象有一个名为“request”的属性并且 Controller ctor arg 被称为“request”时。它以某种方式使 Controller 认为它的请求属性为空。这是导致我看到的错误的原因:

Cannot reuse an 'ApiController' instance. 'ApiController' has to be constructed per incoming message. Check your custom 'IHttpControllerActivator' and make sure that it will not manufacture the same instance.

at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

读一读 How can I enrich object composition in StructureMap without invoking setter injection?

它解释了一个类似的场景。

当然,hyprlinkr 有 HttpRequestMessage 的 ctor arg 称为“request”,所以我确实需要用该属性名称指定匿名对象。

有什么想法吗?

最佳答案

这是一个适合我的 Composition Root:

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;
}

private class Release : IDisposable
{
private readonly Action release;

public Release(Action release)
{
this.release = release;
}

public void Dispose()
{
this.release();
}
}
}

这是我创建容器的方式:

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

这是 InlineDependenciesPropagatingDependencyResolver:

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

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

最后,这是我注册 RouteLinker 的方式:

container.Register(Component
.For<RouteLinker, IResourceLinker>()
.LifestyleTransient());

需要注意的一件事是 ApiController 基类有一个名为 Request 的 HttpRequestMessage 类型的公共(public)属性。如 my book 的第 10.4.3 节所述Windsor 将尝试为每个可写属性分配一个值,如果它具有匹配的组件 - 并且该匹配不区分大小写。

当您将名为 request 的 HttpRequestMessage 传递给 Resolve 方法时,这正是发生的情况,因此您需要告诉 CaSTLe Windsor 它应该放弃 ApiController 的属性注入(inject)。以下是我在基于约定的注册中的做法:

container.Register(Classes
.FromThisAssembly()
.BasedOn<IHttpController>()
.ConfigureFor<ApiController>(c => c.Properties(pi => false))
.LifestyleTransient());

关于c# - ASP Web Api - IoC - 解析 HttpRequestMessage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12977743/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com