我希望有一个关于MVC应用程序中依赖注入的基本问题,我一直无法找到满意的答案。我的应用程序包含一个MVC 3项目,一个服务层类库(SL)和一个数据访问类库(DAL)。 SL和DAL都包含各自的接口和实现。 MVC项目引用了SL和DAL项目。 MVC项目将创建DAL的实现并将其注入到接受DAL接口的SL构造函数中。
我所担心的是为了让SL接受DAL接口作为参数,它还需要对DAL项目的引用(接口碰巧存在但也是实现),这似乎违反了DI,因为现在两者都是MVC和SL项目需要引用DAL程序集。
长话短说,将DAL接口移动到自己的项目中是否更有意义,这样SL只需要引用接口项目而不是实现项目? MVC项目显然需要引用接口和实现项目,DAL也需要引用接口项目。这似乎是一种更干净的做事方式,即使它为我的解决方案增加了另一个项目,这并没有给我带来太多麻烦。我也看到了在SL中存储DAL接口的建议,并且有DAL参考SL,但这对我来说似乎不对。任何见解或建议都表示赞赏。谢谢!
答案 0 :(得分:5)
看看洋葱建筑:
http://jeffreypalermo.com/blog/the-onion-architecture-part-1/
http://jeffreypalermo.com/blog/the-onion-architecture-part-2/
http://jeffreypalermo.com/blog/the-onion-architecture-part-3/
让UI程序集引用所有服务和业务逻辑程序集是完全没错的。服务层显然应该引用不应该依赖于任何更高级别的基础结构程序集。
答案 1 :(得分:2)
真正的组件必须将它们的接口及其实现放在不同的程序集中。
这允许您像加载项一样动态加载适当的实现。通常它也是避免循环引用的唯一方法。作为示例,DAL需要知道模型(业务类),并且模型可能希望通过DAL调用延迟加载依赖模型,这会创建循环引用(.NET禁止循环程序集引用)。如果接口位于单独的程序集中,则DAL和Model程序集都引用了两个接口程序集,并通过构造函数注入依赖项。
// Assembly: Model contracts
public interface IModelA
{
IModelB ModelB { get; }
...
}
public interface IModelB
{
...
}
public interface IModelFactory
{
IModelA CreateModelA();
IModelB CreateModelB();
}
// Assembly: DAL contracts, references Model contracts
public interface IDAL
{
IModelA LoadA(int id);
IModelB LoadB(int id);
}
// Assembly: Model implementation, references Model and DAL contracts
public class ModelA : IModelA
{
private IDAL _dal;
public ModelA (IDAL dal)
{
_dal = dal;
}
private IModelB _modelB;
public IModelB ModelB
{
get {
if (_modelB == null) {
_modelB = _dal.LoadB(5);
}
return _modelB;
}
}
}
// Assembly: DAL implementation, references Model and DAL contracts
public class DAL : IDAL
{
private IModelFactory _modelFactory;
public DAL(IModelFactory _modelFactory)
{
_modelFactory = modelFactory;
}
public IModelA LoadA(int id)
{
IModelA modelA = _modelFactory.CreateModelA();
// fill modelA with data from database
return modelA;
}
public IModelB LoadB(int id)
{
IModelB modelB = _modelFactory.CreateModelB();
// fill modelB with data from database
return modelB;
}
}
答案 2 :(得分:1)
正如规则所说,只要你依赖于接口而不是具体的实现就没关系。所以你可以做的是将你的接口放在不同的程序集中,并在任何你想要的地方引用它们。
答案 3 :(得分:1)
引用具有混凝土类型的程序集可能是个问题,但这取决于您要实现的目标。通过让服务仅依赖于抽象,您可以实现松散耦合的代码。这提高了可维护性。
让BL程序集仅引用包含抽象(而不是实现)的程序集,允许您独立部署部分软件。比如说您希望将软件部署到不同的客户,并且您有多种DA层,但不希望将所有DA风格部署到所有客户(例如,因为他们需要为每个DA层付费,或者可能你试图保护你的知识产权)。
因此,如果分离不是部署的关注点,则不必创建单独的程序集。