英文:
DI between two projects
问题
在项目 B 中,您可以使用 IWorker 的实现,但需要进行注册。您可以通过将 IWorker 添加到项目 B 的依赖注入容器中,以便在项目 B 中使用它。以下是示例代码:
// 在项目 B 中的 Startup.cs 或配置文件中进行注册
services.AddScoped<IWorker, Worker>();
这将使您能够在项目 B 中注入 IWorker,就像您在项目 A 中做的一样,无需重新注册它的所有依赖项。这是一种常见的做法,允许您在多个项目中共享接口的实现,同时保持依赖关系的一致性。
英文:
I have a project A with an IWorker dependency which has many dependencies (context, repositories, etc.). How can I implement IWorker in project B without registering all dependencies? Or what is the correct way to call IWorker in project B?
Example:
Dependency:
public interface IDependency
{
public void SomeMethod();
}
public class SimpleDependemcy : IDependency
{
public void SomeMethod()
{
//Logic
throw new NotImplementedException();
}
}
Worker:
public interface IWorker
{
public void DoWork();
}
public class Worker : IWorker
{
private readonly IDependency _dependency;
public Worker(IDependency dependency)
{
_dependency = dependency;
}
public void DoWork()
{
//Do something
throw new NotImplementedException();
}
}
Registration in project A:
services.AddScoped<IDependency, SimpleDependemcy>();
services.AddScoped<IWorker, Worker>();
I want to use worker in project B like:
public class SomeService
{
private readonly IWorker _worker;
public SomeService(IWorker worker)
{
_worker = worker;
}
}
without any registration or simple services.AddScoped<IWorker, Worker>();
in project B. Is it possible? If not, what is correct way to use IWorker implementation in project B?
答案1
得分: 1
依赖注入在类上起作用,它实际上不关心项目中的事物所在。
最简单的组织方式是在应用程序项目中进行所有的注册,无论它恰好位于哪个项目。但如果你有许多类和多个应用程序使用某个项目,这可能会导致大量的重复代码。
所以你可以将注册委托给每个项目中的一个方法:
// 在项目A中
public static void DoRegistrations(ServiceCollection services){
services.AddScoped<IDependency, SimpleDependemcy>();
services.AddScoped<IWorker, Worker>();
}
...
// 在项目B中
public static ServiceProvider CreateServiceProvider(){
var serviceCollection = new ServiceCollection();
ProjectA.Namespace.DoRegistrations(serviceCollection);
serviceCollection.AddTransient<SomeService>();
var container = serviceCollection.BuildServiceProvider();
return container;
}
一个更高级的解决方案是将注册方法放在实现某个接口的类中,例如:
public interface IModule{
public void DoRegistrations(ServiceCollection services);
}
这使得可以使用反射来查找所有已加载项目中的所有实现,并进行所有的注册。这种模式的一个缺点是对于不熟悉该模式的人来说可能会造成困惑,因此要谨慎使用。
无论你最终选择哪种解决方案,都要考虑编写一些自动化测试来检查是否已完成所有的注册。根据我的经验,缺少注册是运行时故障的常见原因,因此早期检测问题是很有用的。
英文:
Dependency injection work on classes, it does not really care about what project things is in.
The simplest organization is to just make all your registrations in the application project, whatever project that happens to be. But this may cause lots of duplicate code if you have lots of classes and multiple applications using some project.
So you could just delegate registrations to a method in each project:
// In Project A
public static void DoRegistrations(ServiceCollection services){
services.AddScoped<IDependency, SimpleDependemcy>();
services.AddScoped<IWorker, Worker>();
}
...
// In ProjectB
public static ServiceProvider CreateServiceProvider(){
var serviceCollection = new ServiceCollection();
ProjectA.Namespace.DoRegistrations(serviceCollection);
serviceCollection.AddTransient<SomeService>();
var container = serviceCollection.BuildServiceProvider();
return container;
}
An more advanced solution is to put the registration method in a class implementing some interface, for example:
public interface IModule{
public void DoRegistrations(ServiceCollection services);
}
This makes it possible to use reflection to find all implementations in all loaded projects, and do all the registrations. A downside with this pattern is that it can be a big WTF-moment for anyone not familiar with the pattern, so use with care.
Whatever solution you end up with, consider writing some automated tests to check that all registrations have been done. It is my experience that missing registrations is a common source of runtime failures, so detecting problems early is useful.
答案2
得分: 0
看起来像是一种常见的依赖关系设置。为了演示,我将把IWorker
更改为IMyRepository
,将SomeService
更改为MyAppService
。因此,在这个设置中,您通常会创建一个抽象项目,定义某个依赖项应该如何使用以及某个实现应该遵循什么。
我会首先创建包含存储库接口的MyProject.Repository.Abstraction
项目。
然后,我会以特定于平台的方式实现这个接口(比如使用MSSQL和MSSQL依赖项)在MyProject.Repository.Mssql
项目中,将其实现为MyRepostory:IMyRepository
。
类似地,我可以创建MyProject.Services.Abstractions
,但这与问题不相关。我现在可以使用MyProject.Service
项目,引用MyProject.Repository.Abstractions
(而不是特定于平台的实现项目)来实现MyAppService
,该服务利用了IMyRepository
接口。
最后,最高级别的客户端项目MyProject.Client
将引用实现和抽象项目,以实现依赖注入。这样,您可以在其他项目中引用这些抽象。
另外,关于使用这种方法的一点说明,具有最高抽象级别的项目将具有更高的耦合度,使您的项目更接近I曲线(也可参考https://stackoverflow.com/questions/1031135/what-is-abstractness-vs-instability-graph)。
英文:
It seems like a common dependency setup. In order to demonstrate I will change IWorker
to IMyRepository
, and SomeService
to MyAppService
. So, in this setup, you would (generally speaking) create an abstraction project which defines how a certain dependency should be used and what a certain implementation should adhere to.
I would start by creating the MyProject.Repository.Abstraction
project that will contain the repository interface(s).
Then I would implement this interface in a platform specific manner (say MSSQL with MSSQL dependencies) in MyProject.Repositry.Mssql
project as MyRepostory:IMyRepository
Similarly, I could create MyProject.Services.Abstractions
but it is not relevant. I could now use MyProject.Service
project with a reference to MyProject.Repository.Abstractions
(not the platform specific implementation project) to implement MyAppService
which utilizese the IMyRepository
interface.
Finally, the highest level client project, MyProject.Client
would reference both the implementation and the abstraction projects to be able to do the dependency injection. This way you can use the abstractions in other projects as reference.
On another note on using this approach, projects with highest abstraction would have higher afferent coupling getting your projects closer to I curve (see also https://stackoverflow.com/questions/1031135/what-is-abstractness-vs-instability-graph).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论