Asp.net web api 使用Ninject在Web API中捕获和注入HttpRequestMessage

Asp.net web api 使用Ninject在Web API中捕获和注入HttpRequestMessage,asp.net-web-api,ninject,Asp.net Web Api,Ninject,我有一个类需要访问Web API服务中的HttpRequestMessage。目前,我有以下代码来捕获管道中的消息并将其保存以备将来使用(基于和): 公共类ContextCapturingControllerActivator:IHttpControllerActivator { 私有只读IKernel内核; 私有HttpRequestMessage请求消息; 公共上下文CapturingControllerActivator(IKernel内核) { this.kernel=内核; } 公共I

我有一个类需要访问Web API服务中的HttpRequestMessage。目前,我有以下代码来捕获管道中的消息并将其保存以备将来使用(基于和):

公共类ContextCapturingControllerActivator:IHttpControllerActivator
{
私有只读IKernel内核;
私有HttpRequestMessage请求消息;
公共上下文CapturingControllerActivator(IKernel内核)
{
this.kernel=内核;
}
公共IHTTP控制器创建(HttpRequestMessage requestMessage,
HttpControllerDescriptor控制器描述器,
类型控制器类型)
{
this.kernel.Rebind()
.ToConstant(请求消息);
var controller=(IHttpController)this.kernel.GetService(controllerType);
this.requestMessage=requestMessage;
requestMessage.RegisterForDispose(
新版本(()=>this.kernel.Release(controller));
返回控制器;
}
私有类发布:IDisposable
{
私人只读操作发布;
公开发布(行动发布)
{
这个。释放=释放;
}
公共空间处置()
{
这个。释放();
}
}
}
在我的composition根目录中,我配置了
ControllerActivator

kernel.Bind()
.To();
最终结果是,从配置的角度来看,
HttpRequestMessage
被“神奇地”注入到任何被请求的地方,因为它是在
ControllerActivator
中为我们完成的。我无法从我的合成根注入消息。我也不喜欢重新绑定,因为它可以避免每次调用服务时添加新绑定。我怀疑这是由于WebAPI堆栈的单例特性造成的,但是我还没有弄清楚如何正确处理它

一般来说,由于报告的错误(并被忽略),我无法使用Ninject web api的最新不稳定Nuget包

有没有人能提出改进我的代码的正确方法,让代码更清晰,让未来的维护人员的生活更轻松(让我们面对现实吧——我可能会这么做)


谢谢。

以下是我所做的,但我相信这取决于Web API 2.0+

我创建了一个实例类,用于包装当前上下文的http请求:

public class HttpRequestMessageWrapper
{
    private readonly HttpRequestMessage m_httpRequestMessage;

    public HttpRequestMessageWrapper()
    {
        m_httpRequestMessage = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
    }

    public HttpRequestMessage RequestMessage
    {
        get
        {
            return m_httpRequestMessage;
        }
    }
}
然后,我使用请求范围中的ToMethod绑定将HttpRequestMessage绑定到属性

container.Bind<HttpRequestMessage>().ToMethod(ctx => new HttpRequestMessageWrapper().RequestMessage).InRequestScope();
container.Bind().ToMethod(ctx=>newhttprequestmessagewrapper().RequestMessage).InRequestScope();

我尝试了@Mackers提出的最干净的方法。。。。然而,在我的特定场景中,由于时间问题,它无法工作。在我的例子中,我需要将一个对象注入apicontroller ctor,该对象需要HttpRequestMessage。在构造并初始化控制器之前,
HttpContext.Current.Items[“MS_HttpRequestMessage”]
不会被填充,我找不到任何其他方法来访问它。因此,我求助于创建一个定制的DelegatingHandler,并在当前请求消息传入时重新绑定它们

public class CurrentHttpRequestMessageHandler : DelegatingHandler
    {
        [SecuritySafeCritical]
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            UpdateScopeWithHttpRequestMessage(request);

            return base.SendAsync(request, cancellationToken);
        }

        internal static void UpdateScopeWithHttpRequestMessage(HttpRequestMessage request)
        {
            NinjectConfig.GetConfiguredKernel().Rebind<HttpRequestMessage>().ToMethod(ctx => { return request; })
                .InRequestScope();
        }
    }
然后将DelegatingHandler注册到HttpConfiguration:

config.MessageHandlers.Add(new CurrentHttpRequestMessageHandler());

基于Macker的答案,System.Web提供了一个可以使用并简化代码单元测试的工具。在代码中需要请求的任何地方,指定HttpRequestBase类型作为构造函数参数,并使用以下方法注册它:

例如:

Bind<HttpRequestBase>().ToMethod(context => new HttpRequestWrapper(HttpContext.Current.Request));
Bind().ToMethod(context=>newhttprequestwrapper(HttpContext.Current.Request));
统一示例:

container.RegisterType<HttpRequestBase>(new InjectionFactory(_ => new HttpRequestWrapper(HttpContext.Current.Request)));
container.RegisterType(newinjectionfactory(=>newhttprequestwrapper(HttpContext.Current.Request));

我最近也不得不对Ninject(以前也是对StructureMap)做同样的事情,但还没有找到更好的解决方案。@BenFoster我后来改用了Autofac(出于许多原因,不仅仅是这个问题),虽然它提供了一种更干净的方式将HttpRequestMessage注入到运行的代码中,我在内存集成测试中无法访问它。因此,每个DI框架似乎都有自己独特的权衡。有什么突破吗?我有同样的问题…我有同样的问题。使用上述解决方案会导致我的CPU峰值达到100,因为绑定存储在静态字典中。当多个请求通过时,由于每个线程都试图枚举字典,因此它们正在争用(有人找到别的方法吗?@Hudvoy?@BenFoster?
container.RegisterType<HttpRequestBase>(new InjectionFactory(_ => new HttpRequestWrapper(HttpContext.Current.Request)));