加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 17:44:19 所属栏目:百科 来源:网络整理
导读:我正试图用ASP.NET WebAPI设置Castle Windsor. 我也使用Hyprlinkr包(https://github.com/ploeh/Hyprlinkr),因此需要一个HttpRequestMessage的实例注入到我的控制器的一个依赖项中. 我正在跟随Mark Seemann – http://blog.ploeh.dk/2012/04/19/WiringHttpCon
我正试图用ASP.NET WebAPI设置Castle Windsor.

我也使用Hyprlinkr包(https://github.com/ploeh/Hyprlinkr),因此需要一个HttpRequestMessage的实例注入到我的控制器的一个依赖项中.

我正在跟随Mark Seemann – http://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspx的这篇文章,但是我发现尽管API运行,但是当我打电话时,请求就挂起来了.没有错误信息.就好像它处于无限循环.它挂在我的Custom ControllerActivator中的Resolve的调用上

我想我的一些城堡注册错了.如果我删除上述文章中提到的那些,那么我可以成功地调用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);
    }
}

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

所以我设置了一个场景,控制器只需要一个HttpRequestMessage作为一个ctor参数,并发现:

这样做:

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

        public ValuesController(HttpRequestMessage httpReq)
        {
            _httpReq = httpReq;
        }
//IHttpControllerActivator
public IHttpController Create(
            HttpRequestMessage httpRequest,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,new { request = request });

            return controller;

即当anon对象具有称为“请求”的属性,并且控制器ctor arg被称为“请求”时.它以某种方式使控制器认为它的请求属性为null.这是什么原因导致我看到的错误:

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具有称为“request”的HttpRequestMessage的ctor参数,因此我需要使用该属性名称指定anon对象.

有任何想法吗?

解决方法

这是一个适用于我的组合根:
public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

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

    public IHttpController Create(
        HttpRequestMessage request,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 DefaultComponentInstaller())
        .Install(new MyWindsorInstaller());

这里是InlineDependenciesPropagatingDependencyResolver:

public class InlineDependenciesPropagatingDependencyResolver : 
    DefaultDependencyResolver
{
    protected override CreationContext RebuildContextForParameter(
        CreationContext current,true);
    }
}

最后,我如何注册RouteLinker:

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

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

当您将HttpRequestMessage命名请求传递给Resolve方法时,这正是发生的情况,因此您需要告诉Castle Windsor它应该放弃ApiControllers的属性注入.以下是我在公约注册中如何使用:

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读