我有一个 MVC4 应用程序,它在运行时使用反射来加载控制器。这些控制器以及主应用程序使用 Ninject 将内容注入到构造函数中。
每个动态控制器都维护其所需的所有绑定的列表,并将它们存储为主应用程序在运行时加载的 Ninject 模块。
我目前遇到问题,多个动态控制器包含相同的绑定。我希望动态控制器是独立的,所以我不想从控制器项目内部删除绑定,并且我真的不想解析 txt 或 xml 文档来读取所有绑定。
有没有办法删除重复的绑定,或者告诉 Ninject 在有多个绑定时使用它遇到的第一个绑定。
加载所有引用的程序集绑定
public static StandardKernel LoadNinjectKernel(IEnumerable<Assembly> assemblies)
{
var kernel = new StandardKernel();
foreach (var asm in assemblies)
{
asm
.GetTypes()
.Where(t =>
t.GetInterfaces()
.Any(i =>
i.Name == typeof(INinjectBootstrapper).Name))
.ToList()
.ForEach(t =>
{
var ninjectModuleBootstrapper =
(INinjectBootstrapper)Activator.CreateInstance(t);
kernel.Load(ninjectModuleBootstrapper.GetModules());
});
}
return kernel;
}
绑定类
public class NinjectBindings : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IDMSService>().To<DMSService>();
Bind<ICaseManagerRepo>().To<CaseManagerRepo>();
}
}
控制器工厂
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
return (IController)kernel.Get(controllerType);
}
else
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
不,没有。
您可以尝试看看使用
IBindingRoot.Rebind
代替 Bind
是否适合您的需要。
但是我会强烈建议反对它,因为它不适用于:
即使你让它工作,当你有任何条件、参数、OnActivation/OnDeactivation 时,你最终会遇到大量代码重复和难以查明的问题(东西是否工作将取决于模块加载顺序) )。这实在不是一条路。
相反,您可以做人们一直在做的事情:消除重复。 将多个位置需要的绑定移动到它们自己的模块中。 创建某种类型(我们称之为
ControllerModules
)来指定一个控制器需要哪些模块。
不要加载所有模块,而是找到所有 ControllerModules
,从中读取模块,然后加载所有这些模块。
在伪代码中,这可能看起来像:
IEnumerable<Type> modulesToLoad = Assemblies.InPath(...)
.SelectAllClasses()
.InheritingFrom<ControllerModules>
.SelectMany(x => x.RequiredModules)
.Distinct();
IKernel.Load(modulesToLoad);
现在已经过去十多年了,但这也许可以帮助有类似问题的人。
我能够使用此扩展方法避免重复注册:
public IBindingToSyntax<T> TryBind<T>(this IKernel instance)
{
IBindingToSyntax<T> builder;
IBinding binding;
Type type;
type = typeof(T);
binding = instance.GetBindings(typeof(T)).FirstOrDefault;
if (binding == null)
{
binding = new Binding(type);
instance.AddBinding(binding);
}
builder = new BindingBuilder<T>(binding, instance, type.Format);
return builder;
}
用途:
container.TryBind(Of IDotNetService).To(Of DotNetService)()
注意:这不适用于命名绑定,因为我们目前不知道我们将使用命名绑定。