什么是使用Ninject约定绑定的正确方式?

8

我主要使用Ninject进行手动绑定,如下所示。这个方法可以正常工作。

kernel.Bind<TestContext>().ToSelf().InRequestScope();
kernel.Bind<ITestRepository>().To<TestRepository>();

当我尝试使用基于约定的绑定时,我有点困惑,应该在什么时候使用哪个?

我阅读了Ninject文档,但是没有找到很多实例。

根据我的所有Repository类实现IRepository < Model >。因此,如果我想以常规方式进行绑定,则以下代码可以正常工作。

      kernel.Bind(x => x
            .FromAssembliesMatching("*")
            .SelectAllClasses()
            .InheritedFrom(typeof(IRepository<>))
            .BindDefaultInterface());

但是我有点困惑

1. 当我将.FromAssembliesMatching(“*”)更改为.FromThisAssembly()时,它不能正常工作并抛出激活ITestRepository错误。 为什么?

2. 当使用.SelectAllIncludingAbstractClasses().FromAssembliesMatching(“*”)的组合来替换.SelectAllClasses()时,它可以正常工作,为什么

让我解释一下我的代码结构。

IRepository(在DLL 1中)

public interface IRepository<E>
{
    E Get();
}

RepositoryBase (within DLL 1)

 public abstract class RepositoryBase<E> : IRepository<E>
    where E : class
{

    public E Get()
    {
        return System.Activator.CreateInstance<E>(); // this is just for testing
    }
}

测试代码库(位于DLL 2内)

public  interface ITestRepository : IRepository<TestModel>
{

}

public class TestRepository : RepositoryBase<TestModel>, ITestRepository
{

}

现在在 控制器 中(在 DLL 3 中)

    private readonly ITestRepository _testRepository;

    public HomeController(ITestRepository testRepository)
    {
        _testRepository = testRepository;
    }

请告诉我通过传统绑定的最佳方法是什么? 注意:DLL 1、2、3表示不同的项目。

附加信息

错误详情
Server Error in '/' Application.

Error activating ITestRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
 2) Injection of dependency ITestRepository into parameter testRepository of constructor of type HomeController
 1) Request for HomeController

Suggestions:
 1) Ensure that you have defined a binding for ITestRepository.
 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
 3) Ensure you have not accidentally created more than one kernel.
 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
 5) If you are using automatic module loading, ensure the search path and filters are correct.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: Ninject.ActivationException: Error activating ITestRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
 2) Injection of dependency ITestRepository into parameter testRepository of constructor of type HomeController
 1) Request for HomeController

Suggestions:
 1) Ensure that you have defined a binding for ITestRepository.
 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
 3) Ensure you have not accidentally created more than one kernel.
 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
 5) If you are using automatic module loading, ensure the search path and filters are correct.


Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 


[ActivationException: Error activating ITestRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
  2) Injection of dependency ITestRepository into parameter testRepository of constructor of type HomeController
  1) Request for HomeController

Suggestions:
  1) Ensure that you have defined a binding for ITestRepository.
  2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
  3) Ensure you have not accidentally created more than one kernel.
  4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
  5) If you are using automatic module loading, ensure the search path and filters are correct.
]
   Ninject.KernelBase.Resolve(IRequest request) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:359
   Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:197
   Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:165
   Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:114
   Ninject.Activation.Providers.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:96
   System.Linq.WhereSelectArrayIterator`2.MoveNext() +66
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +216
   System.Linq.Enumerable.ToArray(IEnumerable`1 source) +77
   Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:96
   Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:157
   Ninject.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:386
   System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +145
   System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source) +4098209
   Ninject.Web.Mvc.NinjectDependencyResolver.GetService(Type serviceType) in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectDependencyResolver.cs:56
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +41

[InvalidOperationException: An error occurred when trying to create a controller of type 'MVCPluginApproach.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +179
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +80
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +74
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +197
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +49
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +50
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

根据我的基本理解...错误的原因是多个程序集,而不是单个程序集。所以当我尝试通过 .FromThisAssembly() 绑定它时,Ninject 无法解析它。这是真的吗?


你能提供准确的异常信息吗?包括消息和堆栈跟踪吗?此外,还有更多文档:https://github.com/ninject/ninject.extensions.conventions/wiki/_pages - BatteryBackupUnit
@BatteryBackupUnit:我更新了我的帖子,请看一下。 - Shubhajyoti Ghosh
1
.FromThisAssembly() 只会绑定在定义绑定的程序集中的类。由于您在多个程序集中拥有存储库,仅针对“此程序集”的约定将无法适用于其他程序集。 - BatteryBackupUnit
.SelectAllIncludingAbstractClasses() 这个类怎么样,我应该使用它吗? - Shubhajyoti Ghosh
2
不,我不这么认为。只有在动态生成实现时才有意义,例如作为代理。文档中也提到了这一点:https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Components - BatteryBackupUnit
1个回答

11

以下是我使用 Ninject 3.0 的方法...

//binding rules in all assemblies named "My.<anything>.dll"
kernel.Bind(x => x.FromAssembliesMatching("My.*.dll")
                    .SelectAllClasses()
                    .BindAllInterfaces()
            );

// basic interface
ISomething<T> { /* code for interface */ }

// implementation of interface
Something<T> { /* implement interface */ }

// get an instance of Something<AnyType> by asking for ISomething<AnyType>
var something = kernel.Get<ISomething<SomeType>>();

那么您需要做的就是声明更多的接口和类。

当您想要使用抽象类/继承时,最简单的方式而不会使规则复杂化,就是像这样做...

ICustomSomething : ISomething<SomeType> { /* extended interface parts */ }

CustomSomething : Something<SomeType>, ICustomSomething { /* implement ICustomSomething */ }

不需要新的依赖规则。这里使用的约定基本上意味着,Ninject的核心将查找I...,然后通过查找名称减去I前缀的类型来匹配它,作为一个经验法则,因此对于您定义的每个新类/类型,只需声明一个接口即可,ninject无需更多信息。

如果您想要执行更复杂的操作(比如说多态场景),那么我建议让ninject创建一个工厂,您将类型提供给该工厂,然后从中生成正确的类型。

例如,您可以拥有...

kernel.Bind<ISomething<>>().ToMethod(() => () { kernel.Get<SomeFactory>().Get<T>() });

如果这里的代码不完全准确,抱歉,因为它都是从我的脑海中提取出来的,但你应该能够理解它的意思 :)

编辑: 观察...... 值得注意的是,这通常不起作用:

kernel.Bind(x => x.FromAssembliesMatching("*") ...);

指令 ".FromAssembliesMatching("*")" 会直接挑选 bin 文件夹中的所有程序集,并尝试为它们构建规则,我经常发现一些第三方创建的程序集无法这样处理,您可能还有 .Net 的组件在 bin 文件夹中,而您不希望为其构建规则。

我曾经尝试这样做,但遇到了一些问题,所以我决定创建自己的程序集命名约定,例如:

MyCorp.Core.dll; MyCorp.Common.dll; MyCorp.AppName.Repositories.dll; MyCorp.AppName.Services.dll;

因此,当我进行绑定时,只会绑定这些程序集,而不是所有的。

.FromAssembliesMatching("MyCorp.*.dll")

除此之外,我发现 Ninject 几乎没有什么问题,它是相当基础的东西!!


感谢详细的描述。 - Shubhajyoti Ghosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接