我有一个 ASP.NET MVC 应用 SignalR 和 WebAPI 。该应用程序使用 Ninject 进行依赖注入,但显然SignalR和WebAPI正在获得不同的内核,因此它无法共享应该为所有应用程序共享的单个对象。
我可以在日志中清楚地看到SignalR获取连接请求时如何创建实例,以及WebAPI获取请求时的其他实例。
我想在这三个元素之间共享相同的Ninject内核,所以我可以拥有独特的单例。
这是我到目前为止所做的:
我做的第一件事是创建NinjectModule
声明绑定:
public class MyDependencyModule: NinjectModule
{
public override void Load()
{
var binding = Bind<MustBeSingleton>().ToSelf();
binding.OnActivation((ctx, o) =>
{
Debug.Print("Registering item " + o.GetHashCode());
HostingEnvironment.RegisterObject(o);
});
binding.OnDeactivation(o =>
{
Debug.Print("Unregistering game connection " + o.GetHashCode());
});
binding.InSingletonScope();
}
}
我还为Ninject创建了一个包装器,以便将其插入WebAPI:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
this.resolver = resolver;
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
另外,我为SignalR创建了另一个包装器:
public class SignalRNinjectDependencyResolver : DefaultDependencyResolver
{
private readonly IKernel _kernel;
public SignalRNinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public override object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType).Concat(base.GetServices(serviceType));
}
}
然后我创建了一个执行所有配置的Ninject内核:
public class ApplicationDependencies:StandardKernel
{
public ApplicationDependencies()
:base(new MyDependencyModule())
{
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(this);
Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(this);
}
}
MVC应用程序使用NinjectHttpApplication
作为基类,所以我指出必须以这种方式使用的内核:
public class MvcApplication : Ninject.Web.Common.NinjectHttpApplication
{
protected override Ninject.IKernel CreateKernel()
{
return new ApplicationDependencies();
}
}
此外,在SignalR配置中,我指定了解析器:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR<MyPersistentConnection>("/updates", new ConnectionConfiguration()
{
Resolver = GlobalHost.DependencyResolver
});
}
}
(我也试过没有指定解析器,它也不起作用。)
有什么想法吗?
干杯。
答案 0 :(得分:2)
为了保持这3件事有效......你应该检查这些参考:
Web API
+ Ninject
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/ SignalR
+ Ninject
https://github.com/SignalR/SignalR/wiki/Extensibility(最后一部分:
使用ASP.NET MVC时,首先配置SignalR,然后配置ASP.NET MVC)对于第二个,我重构了一点,因为我需要SignalR
Dependency Resolver的内核
// Route SignalR.
GlobalHost.DependencyResolver = NinjectWebCommon.GetSignalrResolver();
RouteTable.Routes.MapHubs();
我在GetSignalrResolver
内定义了NinjectWebCommon
,如下所示:
public static Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver GetSignalrResolver()
{
return new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(bootstrapper.Kernel);
}
注意:有2个不同的DependencyResolver
:Web API
(1)分配给GlobalConfiguration.Configuration.DependencyResolver
,另一个分配给SignalR
(2) )分配到GlobalHost.DependencyResolver
答案 1 :(得分:1)
我在另一篇文章中找到了答案:Singleton Scope binding not working as intended
不是绑定为单身,而是必须使用“ToConstant”:
var binding = Bind<MustBeSingleton>().ToConstant(new MustBeSingleton());
我使用相同的依赖注入上下文,使用ASP.NET MVC,WebAPI和SignalR创建了一个简单的演示项目。
https://drive.google.com/file/d/0B52OsuSSsroNX0I5aWFFb1VrRm8/edit?usp=sharing
Web应用程序包含一个页面,该页面显示了一个对象的AppDomain和GetHashCode,该对象在三个框架中应该是唯一的,结果类似于:
Dependency Test
Framework IMySingletonService instance
MVC AppDomainId:2 / HashCode:5109846
WebAPI AppDomainId:2 / HashCode:5109846
SignalR AppDomainId:2 / HashCode:5109846
其他问题是,Ninject正在处理我的单身因为是IDisposable。我真的不明白为什么会这样,但那是另一场战争。
干杯。
答案 2 :(得分:0)
为了对WebApi和SignalR使用依赖项解析器,您需要实现一个如下所示的类:
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()
{ }
}
然后在您的启动类中,您应该为WebApi和SignalR注册NinjectDependencyResolver,如下所示:
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);
}