虽然DI
和IoC containers
的概念相当直接但我似乎在努力实施。我有一个四层应用程序,其中UI Layer
到Service Layer
使用IoC
并且似乎工作正常,但Service Layer
到Business Layer
是绝对的痛苦。
我专门阅读了许多文章Ninject
和Class Libraries
,但我仍然无法正确实施。我希望你善良的人能指出我正确的方向......
典型的分层流程: UI图层>服务层>业务层>数据层
因此,如果可以显示我的UI Layer
到Service Layer
的实施情况:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IApiAuthorizationService>().To<ApiAuthorizationService>();
}
public class DebateController : ApiController
{
private IApiAuthorizationService _iApiAuthorizationService;
public DebateController(IApiAuthorizationService iApiAuthorizationService)
{
_iApiAuthorizationService = iApiAuthorizationService;
}
}
正如您所看到的,UI Layer
是一个WebApi
项目,它注入 IApiAuthorizationService ,这里没什么特别复杂的。
因此,一旦构建了 ApiAuthorizationService ,它就会指向许多存储库,但是现在我将添加一个只有该存储库的片段。
我们现在位于服务层,它引用了业务层:
public class ApiAuthorizationService : IApiAuthorizationService
{
private IApiAuthTokenRepository _iApiAuthTokenRepository;
public ApiAuthorizationService(IApiAuthTokenRepository iApiAuthTokenRepository)
{
_iApiAuthTokenRepository = iApiAuthTokenRepository;
}
}
此时我在Service Layer
上安装了 Ninject ,并创建了一个将创建绑定的类:
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<IApiAuthTokenRepository>().To<ApiAuthTokenRepository>();
}
}
基本上我已经陷入困境,不知道该去哪里,我再次阅读了很多帖子,但很多帖子都使用Console Applications
进行演示,Class Library
没有入口点。我想的是添加Startup.cs
来初始化绑定。
有人能用一些演示代码指出我正确的方向吗?
谢谢。
答案 0 :(得分:0)
主要用于实例化DI容器并配置它的位置应该是应用程序入口点。这意味着你永远不会在库中实现DI容器。也就是说,入口点需要知道所有依赖关系并相应地配置它们。 Mark Seeman有一篇关于原则的博客文章:Composition Root。
现在,在大多数项目中,我在某种程度上违反了这种方法 - 这有利有弊。 Ninject(和Autofac ...)具有模块的概念。模块是一组绑定/注册,因此它是(部分)容器配置规范。这些可以添加到库中并在组合根中获取。 该概念记录在案here。
示例:
NinjectModule
s var kernel = new StandardKernel()
和kernel.Load(AppDomain.CurrentDomain.GetAssemblies());
NinjectModule
s NinjectModule
s NinjectModule
s 你什么时候不这样做?
在这些情况下,您应严格遵守Mark的Composition Root概念。
答案 1 :(得分:-1)
您可以执行您正在执行的操作,并创建一个注册服务的位置。那会有用。但是,如果您认为应用程序有益处,这里的高级方法也可以使用。
一般的想法是依赖注入库和应用程序之间的一个层。我们将此层称为IServiceContainer。
public class ServiceContainer : IServiceContainer
{
// internally manages ninjects kernel via methods such as...
public void RegisterType<TService, TInstance>();
public void RegisterTypes(Assembly assembly);
// ultimately, this just segregates Ninject from your app so there are no Ninject dependencies
}
现在,您可以通过IServiceContainer.RegisterType手动添加要注册的所有内容,或者,您可以使用属性更自动地执行某些操作,例如....
[ServiceRegistration(typeof(IApiAuthorizationService))]
public class ApiAuthorizationService : IApiAuthorizationService
{
private IApiAuthTokenRepository _iApiAuthTokenRepository;
public ApiAuthorizationService(IApiAuthTokenRepository iApiAuthTokenRepository)
{
_iApiAuthTokenRepository = iApiAuthTokenRepository;
}
}
IServiceContainer.RegisterTypes的实现将扫描ServiceRegistrationAttribute中的所有类型。对于它们中的每一个,现在您可以通过IServiceContainer.RegisterType()自动注册服务类型和实现类型
这可以根据需要采取或不采取。
至于如何解决“在N层应用程序中使用”的问题...... 您可以在每个程序集中提供单个接口实现,该实现知道如何注册其所有需求,并且该实现可能依次从它所依赖的另一个程序集调用相同的接口实现。通过这种方式,您可以允许每个组件沿其依赖组件的注册向前移动。这是一个长期战略,可能会为您提供一些有用的想法。
这是一个粗略的概念,看起来像什么(记住,你会在每个装配中有一个)......
public class AutoRegistration: IAutoRegistration
{
public void Register(IServiceContainer container)
{
// where the type of Add<> is IAutoRegistration
container.Add<SomeDependentNamespace.AutoRegistration>();
container.Add<SomeOtherDependentNamespace.AutoRegistration>();
}
}
IServiceContainer将简单地收集添加的所有不同的IAutoRegistration(它在.Add()中知道每个TAutoRegistration的那个组件,并且可以扫描属性的类型,如前所示,并逐个注册类型