【发布时间】:2015-04-27 15:00:34
【问题描述】:
我有一个带有 SignalR 和 WebAPI 的 ASP.NET MVC 应用程序。该应用程序使用 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
});
}
}
(我也尝试过不指定解析器,它也不起作用)。
有什么想法吗?
干杯。
【问题讨论】:
-
前段时间我遇到了同样的问题,我切换到 Unity for Web App / Web API 以使用相同的解析器内核。我知道你也可以在 Ninject 中实现这一点,但我发现我必须使用 NinjectMVC3 和 NinjectWebAPI 进行一些黑客攻击。希望这会有所帮助!
标签: asp.net-mvc-4 dependency-injection asp.net-web-api ninject signalr