我有两个使用以下Unity逻辑的项目:
container.RegisterType<IUnitOfWork, MyDbContext>(
new HierarchicalLifetimeManager(),
new InjectionFactory(
c => new MyDbContext(configurationService.MySqlConnectionString)
)
);
container.RegisterType<DbContext, MyDbContext>(
new HierarchicalLifetimeManager()
);
第一个项目是一个使用Unity.MVC4包的Web应用程序,因此有一个定制的DependencyResolver执行一些工作 - 这完美地工作。
第二个是非Web应用程序,因此使用普通的Unity软件包实例,但在使用 MyDbContext 进行调用时出错。
是个例外System.Data.Entity.Core.MetadataException:指定的架构不是 有效。错误:EntityDataModel.MyProject.ssdl(2,2):错误0152: 实体框架提供程序类型 “System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer,Version = 6.0.0.0,Culture = neutral, 'System.Data.SqlClient'的PublicKeyToken = b77a5c561934e089' 无法加载ADO.NET提供程序。确保提供程序程序集 正在运行的应用程序可用。看到 http://go.microsoft.com/fwlink/?LinkId=260882了解更多信息。
我已经设置了两个项目来调用相同的服务,这是在一个单独的项目中,试图将问题的根源与第二个项目的Unity逻辑隔离开来。我还应该注意到我正在使用Entity Framework 6作为ORM。
我的问题是我需要Unity代码才能使第二个项目工作,或者我可以添加一些app.config条目来引用EF程序集吗?
更新 经过一些额外的工作后,我注意到如果我引用DbContext程序集:
在第二个项目中问题消失了。我想避免引用这些程序集,因为我的客户端项目不应该对ORM有任何了解。
我也尝试更新连接字符串,所以我手动指定了ORM项目的程序集(我的EDMX文件所在的位置),如StackOverflow question中所述但是没有任何区别。
元数据= RES://nameOfDll/Model.csdl | RES://nameOfDll/Model.ssdl | RES://nameOfDll/Model.msl
答案 0 :(得分:2)
你正在以正确的方式做到这一点。
使用DI,您可以从应用程序中删除依赖项。这样您就可以获得“存储库不可知”应用程序。你已经有效地完成了它。至少在'声明'依赖项的项目上。
但是,当应用程序必须运行时,您需要指定将用于“声明的”抽象依赖项(接口,抽象类)的具体对象。
您可以通过注册将用于每个抽象依赖项的对象类型来完成此操作。在您的示例中,当IUnitOfWork
或DbContext
时,会提供MyDbContext
的实例。
因此,“声明”依赖项的项目完全独立于特定的实现。
但是,当您注册依赖类型时,您将失去这种独立性。
让我们看一个例子:
如果我说“我口渴,我需要喝酒,但我不介意喝什么”,我依赖任何饮料,而不是特定的饮料。但如果我说“当我口渴时,我想喝可乐”我依赖可乐。
第一部分是依赖的抽象定义:“任何饮料”(如抽象IUnitOfWork
或DbContext
)。第二部分是具体的依赖:“可乐”(如MyDbContext
)。
所以,只要我没有说明我想喝的东西,我就独立于可乐。但是一旦我说出来,我就会依赖。
也许您正在寻找的是一种在运行时更改存储库的方法。您可以这样做:不要在代码中注册依赖项,因为您需要使用所选的具体类型来引用项目。在外部配置(即文件)中执行此操作,以便您可以在不参考依赖项的情况下编译项目,并在运行时提供所需的程序集。
注意:当我说“声明”时,我的意思是使用任何模式来注入依赖项,例如构造函数注入(大多数建议)或任何其他注入模式(属性依赖项)。