题
首先,我使用 Ninject 1.5。我有两个项目:Web 项目和类库。我的 DI 配置位于 Web 项目中。在我的类库中,我定义了以下内容:
public interface ICacheService<T>
{
string Identifier { get; }
T Get();
void Set( T objectToCache, TimeSpan timeSpan );
bool Exists();
}
然后是一个名为的具体类 类别缓存服务.
在我的网络项目中,我绑定了两者:
Bind( typeof( ICacheService<List<Category>> ) ).To( typeof(CategoryCacheService)).Using<SingletonBehavior>();
在我的类库中,我有 HtmlHelper 类的扩展方法,例如:
public static class Category
{
[Inject]
public static ICacheService<List<Category>> Categories { get; set; }
public static string RenderCategories(this HtmlHelper htmlHelper)
{
var c = Categories.Get();
return string.Join(", ", c.Select(s => s.Name).ToArray());
}
}
我被告知你不能注入静态属性,相反我应该使用 内核.Get<>() - 然而...由于上面的代码位于类库中,我无权访问内核。我怎样才能从这一点获得内核或者有更好的方法来做到这一点?
解决方案
好问题。
使用 DI 的一半想法是从注入的代码中消除对实例化行为的关注/微调。因此,改变 Category
类不再是 static
, ,在构造函数中声明其依赖项,并让客户端代码将其拼接在一起。
关于如何访问它(如果您确实确定这是一个好主意)...一般来说,您的情况的想法是创建一个 CacheServiceResolver
并注册它[在您的Web项目中]。然后将其传递给 Kernel
正在构建的实例。这样你的 DLL 就只绑定到你的接口 CacheServiceResolver
.
经常使用的另一种方法是在全球某处设置最后手段“服务定位器”设施,它公开“GlobalGet”。但这通常是一个坏主意,只能用于临时管道胶带目的。
另一件需要注意的事情是公共服务定位器,它允许人们创建一个容器中立的库,尽管在 EL 之外,您不会发现很多用法,因为 你不应该真正展示你的容器.
另一种选择是要求 Func<T>
工厂方法和 Bind
到一个解析它的 lambda,从代码中提取该查找。
编辑:在 Ninject 2 中,不需要显式传入 Kernel
正如我所说的实例 - 人们可以简单地要求一个 IKernel
在你的构造函数中,你会得到它,无论解析请求是否明确地传递一个。
编辑2:对我的回答真的很不满意,试图使其更通用,但又不会对其进行过多的破坏。总结一下,理想的选项通常按以下顺序排列:
- 无容器伪影,将缝合留给客户
- 提供容器中立扩展点,专门用于使用图书馆领域通用语言中的术语代替中立的抽象容器术语,在图书馆环境中专门完成某些任务
- 提供一种容器中立的集成方法,如公共服务定位器
- 然后才考虑让人们需要
- 了解你的容器
- 了解你的容器
其他提示
在web项目运行从包管理控制台中执行以下命令。
Install-Package Ninject.MVC3
您应该结束了在App_Start文件夹NinjectWebCommon模块。
在接近底部,你可以添加你喜欢的依赖关系如下:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IPeopleRepository>().To<PeopleRepository>();
}
从您的类库项目运行以下命令:
Install-Package Ninject
这是如何与从类库存储库注入服务:
public class PeopleService : IPeopleService
{
private readonly IPeopleRepository _peopleRepository;
[Inject]
public PeopleService(IPeopleRepository peopleRepository)
{
this._peopleRepository = peopleRepository;
}
}