Asp.net 具有Web Api、信号器、MVC和OWIN的Ninject

Asp.net 具有Web Api、信号器、MVC和OWIN的Ninject,asp.net,signalr,ninject,asp.net-web-api,owin,Asp.net,Signalr,Ninject,Asp.net Web Api,Owin,我在我的web应用程序中使用一个Ninject DI,并使用Asp.Net堆栈中的一系列技术(MVC、web Api 2、SignalR) 我已通过以下方法使DI适用于所有正在使用的技术: public static class NinjectWebCommon { private static readonly Bootstrapper bootstrapper = new Bootstrapper(); /// <summary> /// Starts

我在我的web应用程序中使用一个Ninject DI,并使用Asp.Net堆栈中的一系列技术(MVC、web Api 2、SignalR)

我已通过以下方法使DI适用于所有正在使用的技术:

public static class NinjectWebCommon 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }
    
    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }
    
    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    internal static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();

        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);

        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
        DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));

        // Binding services here
    }        
}
到我的
OwinStartup
类。Web Api的DI已停止工作

我开始搜索合适的解决方案,找到了
Ninject.Web.WebApi.OwinHost
包。因此,为了让单个内核解决所有技术的依赖关系,我做了以下更改:

在OwinStartup中:

app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
app.UseNinjectWebApi(config);
在NinjectWebCommon中:

//[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(App.TradingServer.ConfiguratorApp.App_Start.NinjectWebCommon), "Start")]
//[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(App.TradingServer.ConfiguratorApp.App_Start.NinjectWebCommon), "Stop")]
这些行被禁用,以避免两次初始化内核

这修复了Web Api的DI,但不适用于SignalR。当客户端尝试连接到集线器时,我遇到以下异常:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.AspNet.SignalR.PersistentConnection.ProcessNegotiationRequest(HostContext context)
   at Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequest(HostContext context)
   at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.ProcessRequest(HostContext context)
   at Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequest(IDictionary`2 environment)
   at Microsoft.AspNet.SignalR.Owin.Middleware.HubDispatcherMiddleware.Invoke(IOwinContext context)
   at Microsoft.Owin.Infrastructure.OwinMiddlewareTransition.Invoke(IDictionary`2 environment)
   at Microsoft.Owin.Mapping.MapMiddleware.<Invoke>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at System.Web.Http.Owin.HttpMessageHandlerAdapter.<InvokeCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Ninject.Web.Common.OwinHost.OwinBootstrapper.<Execute>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.<RunApp>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.<DoFinalWork>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Owin.Host.SystemWeb.Infrastructure.ErrorState.Rethrow()
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar)
   at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar)
   at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) | RuntimeMethodInfo.UnsafeInvokeInternal => RuntimeMethodHandle.InvokeMethod => Application.Application_Error
与此呼叫冲突:

GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
因此,问题描述仅限于此。当我使用以下模式时,信号器停止工作:

public void Configuration(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();
    WebApiConfig.Register(config);

    app.UseNinjectMiddleware(CreateKernel);
    app.UseNinjectWebApi(config);

    GlobalHost.HubPipeline.AddModule(new GlobalSignalRExceptionHandler());
    app.MapSignalR();
}


private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();

    GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
    DependencyResolver.SetResolver(new Ninject.Web.Mvc.NinjectDependencyResolver(kernel));

    return kernel;
}
但是如果我评论这句话

    //GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);

信号员又开始工作了。当然,集线器内部没有注入。

为了同时使用WebApi和Signal的依赖项解析器,您需要实现一个如下所示的类:

    public class NinjectDependencyResolver : Microsoft.AspNet.SignalR.DefaultDependencyResolver,
    System.Web.Http.Dependencies.IDependencyResolver
{
    public readonly IKernel Kernel;

    public NinjectDependencyResolver(string moduleFilePattern)
        : base()
    {
        Kernel = new StandardKernel();
        Kernel.Load(moduleFilePattern);

    }
    public override object GetService(Type serviceType)
    {
        var service = Kernel.TryGet(serviceType) ?? base.GetService(serviceType);
        return service;
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        IEnumerable<object> services = Kernel.GetAll(serviceType).ToList();
        if (services.IsEmpty())
        {
            services = base.GetServices(serviceType) ?? services;
        }
        return services;
    }

    public System.Web.Http.Dependencies.IDependencyScope BeginScope()
    {
        return this;
    }

    public void Dispose()
    { }
}
public void Configuration(IAppBuilder app)
{
    var dependencyResolver = new NinjectDependencyResolver("*.dll");

    var httpConfiguration = new HttpConfiguration();
    httpConfiguration.DependencyResolver = dependencyResolver;
    app.UseWebApi(httpConfiguration);

    var hubConfig = new HubConfiguration { Resolver = dependencyResolver };
    app.MapSignalR(hubConfig);
}

最后,我设法获得了支持OWIN管道、WebApi、MVC和signar的工作Ninject配置

当我发布这个问题的时候,我已经有了一个解决办法(在信号集线器中禁用DI),所以我决定不再在这个问题上浪费时间,继续前进

但当我尝试用我的启动类运行OWIN内存测试服务器时,发现DI不工作。调用CreateKernel方法太晚,导致创建sengleton范围中使用的对象的多个实例

在使用了不同的初始化变体之后,我让DI为OWIN测试服务器工作,它还修复了依赖信号器的解析器

解决方案:

我停止使用包Ninject.Web.Common.OwinHost和Ninject.Web.WebApi.OwinHost,因此这些调用已从我的配置方法中删除:

//app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
//app.UseNinjectWebApi(config);
相反,我做了以下工作:

public void Configuration(IAppBuilder app)
{
    ConfigureOAuth(app);

    HttpConfiguration config = new HttpConfiguration();
    WebApiConfig.Register(config);
    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

    NinjectWebCommon.Start();
    config.DependencyResolver = new NinjectDependencyResolver(NinjectWebCommon.bootstrapper.Kernel);
    app.UseWebApi(config);

    app.MapSignalR();
}

public static class NinjectWebCommon 
{
    private static bool _isStarted;

    internal static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        // When creating OWIN TestService instances during unit tests
        // Start() method might be called several times
        // This check ensures that Ninject kernel is initialized only once per process
        if (_isStarted)
            return;

        _isStarted = true;

        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    internal static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        // DI for SignalR
        GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
        // DI for MVC
        DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));

        // Binding code here
        kernel.Bind<Something>().ToSelf().InSingletonScope();
    }        
}
public void配置(IAppBuilder应用程序)
{
配置OAuth(应用程序);
HttpConfiguration config=新的HttpConfiguration();
WebApiConfig.Register(配置);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
NinjectWebCommon.Start();
config.DependencyResolver=新的NinjectDependencyResolver(NinjectWebCommon.bootstrapper.Kernel);
app.UseWebApi(配置);
app.mapsigner();
}
公共静态类NinjectWebCommon
{
已启动专用静态布尔;
内部静态只读引导程序引导程序=新引导程序();
/// 
///启动应用程序
/// 
公共静态void Start()
{
//在单元测试期间创建OWIN TestService实例时
//Start()方法可能被多次调用
//此检查确保每个进程只初始化Ninject内核一次
如果(_已开始)
返回;
_IsStart=true;
初始化(CreateKernel);
}
/// 
///创建将管理应用程序的内核。
/// 
///创建的内核。
内部静态IKernel CreateKernel()
{
var kernel=新的标准内核();
注册服务(内核);
返回内核;
}
/// 
///在这里加载您的模块或注册您的服务!
/// 
///内核。
私有静态无效注册服务(IKernel内核)
{
//信号机用DI
GlobalHost.dependencyrolver=新的Microsoft.AspNet.signal.Ninject.ninjectdependencyrolver(内核);
//MVC的DI
SetResolver(新的NinjectDependencyResolver(内核));
//这里绑定代码
kernel.Bind().ToSelf().InSingletonScope();
}        
}

必须在依赖项注入配置之后配置Signal。因此,在OWIN启动类中,确保在设置MVC依赖项解析程序(
System.Web.MVC.DependencyResolver
)、WebApi依赖项解析程序(
System.Web.Http.GlobalConfiguration.Configuration.Configuration.DependencyResolver
)和信号依赖项解析程序后调用
app.mapsignar()
Microsoft.AspNet.signal.GlobalHost.DependencyResolver
)如果信号器使用的DI容器分发多个预期为单例的特定类型的实例,则会引发堆栈跟踪。这可能是由于各种原因造成的,其中一个原因是
GlobalHost。DependencyResolver
在使用默认信号器容器后会被修改。在OWIN中,您可能需要调用
Map信号器
后期开发。例如,Nancy
app.UseNancy(o=>o.PerformPassThrough=c=>c.Request.Path.ToUpperInvariant().StartsWith(“/signar”)).mapsigner()
。真是噩梦,你是怎么弄明白的!DependencyResolver.SetResolver中的DependencyResolver(新的NinjectDependencyResolver(内核))在哪里来自哪里?这与GlobalHost不同吗?这是在
System.Web.Mvc
命名空间中定义的单例。您的IsEmpty()来自哪里?我刚才使用的是
服务.Count()==0
,还有Dispose()是对DefaultDependencyResolver的重写。使用从ModelValidatorProvider到NinjectDefaultModelValidatorProvider的绑定激活ModelValidatorProvider时出错检测到两个服务的构造函数之间存在周期性依赖关系。:PI喜欢此解决方案,我发现我必须去掉Ninject.Web.*才能工作。
//app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
//app.UseNinjectWebApi(config);
public void Configuration(IAppBuilder app)
{
    ConfigureOAuth(app);

    HttpConfiguration config = new HttpConfiguration();
    WebApiConfig.Register(config);
    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

    NinjectWebCommon.Start();
    config.DependencyResolver = new NinjectDependencyResolver(NinjectWebCommon.bootstrapper.Kernel);
    app.UseWebApi(config);

    app.MapSignalR();
}

public static class NinjectWebCommon 
{
    private static bool _isStarted;

    internal static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        // When creating OWIN TestService instances during unit tests
        // Start() method might be called several times
        // This check ensures that Ninject kernel is initialized only once per process
        if (_isStarted)
            return;

        _isStarted = true;

        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    internal static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        // DI for SignalR
        GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
        // DI for MVC
        DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));

        // Binding code here
        kernel.Bind<Something>().ToSelf().InSingletonScope();
    }        
}