我正在使用Hangfire库设置TaskScheduler。 现在,这些任务已注册为服务。有许多不同的工作/任务。 在服务界面中,对每个任务实现都有这样的引用:
using System.Threading.Tasks;
namespace Domain.Interfaces
{
public interface IService
{
Task DoStuff1();
Task DoStuff2();
//etc..
}
}
此服务已在Startup类中注册,例如:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IService, Service>();
}
问题现在我必须在服务类中具有每个任务的所有代码。 我宁愿在服务界面中有1个引用,例如:
using System.Threading.Tasks;
namespace Domain.Interfaces
{
public interface IService
{
Task RunTask();
}
}
RunTask()将被在从Service继承的每个单独的子类中进行的实际工作所覆盖(从而实现IService) 这样,我可以将所有任务代码保持良好且独立,但是通过诸如
之类的通用函数调用来启动这些任务 _service.RunTask();
将所有不同的任务注册为单独的服务也不是一个好选择。我不要:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IService, Task1Service>();
services.AddTransient<IService, Task2Service>();
services.AddTransient<IService, Task3Service>();
//etcetc..
}
在Hangfire中,这些已注册为重复性工作,例如:
RecurringJob.AddOrUpdate<Worker>(system, w => w.DoStuff1(),appSettings.AuthInterval, TimeZoneInfo.Local);
RecurringJob.AddOrUpdate<Worker>(system, w => w.DoStuff2(),appSettings.AuthInterval, TimeZoneInfo.Local);
Worker类将使用注入的IService执行任务,例如:
public async Task DoStuff1()
{
await _service.DoStuff1();
TextBuffer.WriteLine("DoStuff 1 was completed");
}
我想大致保持这种结构,但是我想指定实际上将注入哪个服务,以便Worker只需包括:
public async Task DoStuff()
{
await _service.RunTask(); //would run the correct task based on the service injected ??
}
如何最好地做到这一点? 我对Dependecy注入概念比较陌生,但认为我有一个基本的了解。 我主要想:
谢谢!
答案 0 :(得分:1)
您可以像不使用Hangfire一样组成各个服务的类。如果两个服务做不同的事情,那么它们可能应该是单独的类。
您可以根据其特定类型将其注册为循环作业:
RecurringJob.AddOrUpdate<SomeService>(
system,
s => s.DoWhateverThisServiceDoes(),
appSettings.AuthInterval,
TimeZoneInfo.Local);
RecurringJob.AddOrUpdate<OtherService>(
system,
o => o.DoOtherThing(),
appSettings.AuthInterval,
TimeZoneInfo.Local);
如果您决定不希望这两个服务作为单独的任务运行,而是作为单个任务的一部分运行,该怎么办?您也可以这样做:
public class CompositeService
{
private readonly SomeService _someService;
private readonly OtherService _otherService;
public CompositeService(SomeService someService, OtherService otherService)
{
_someService = someService;
_otherService = otherService;
}
public async Task DoCompositeThing()
{
await Task.WhenAll(
_someService.DoWhateverThisServiceDoes(),
_otherService.DoOtherThing());
}
}
RecurringJob.AddOrUpdate<CompositeService>(
system,
s => s.DoCompositeThing(),
appSettings.AuthInterval,
TimeZoneInfo.Local);
一个关键点是,无论您决定单独注册它们还是创建一个执行两者的任务,都无需更改编写单个类的方式。要决定将它们设置为一个类还是单独的类,您可以应用“单一责任原则”,还应考虑使它们更易于理解和进行单元测试的内容。就个人而言,我倾向于编写较小的,单独的类。
另一个因素是各个类可能具有自己的依赖关系,例如:
public class SomeService
{
private readonly IDependOnThis _dependency;
public SomeService(IDependOnThis dependency)
{
_dependency = dependency;
}
public async Task DoWhateverThisServiceDoes()
{
// uses _dependency for something
}
}
如果将类分开放置,则更易于管理。如果它们全都在一个类中,并且不同的方法依赖于不同的事物,那么您最终可能会遇到许多不相关的依赖关系,并且方法会挤在一个类中。没有必要这样做。即使我们希望所有功能由一个类“协调”,我们仍然可以将其编写为单独的类,然后使用另一个类将它们组合在一起。
这是有关依赖项注入模式的重要内容之一。它限制了我们一次需要阅读和理解的代码量。一个类可能具有一个或多个依赖项。当您查看该类时,您不必考虑那些依赖项是否具有它们自己的依赖项。嵌套依赖项可能会有所不同。但是,当我们查看一个类时,我们只需要考虑它的作用以及如何使用其依赖关系。 (这也是为什么它使单元测试更容易的原因。)
无论您创建了多少类,都需要向IServiceCollection
注册所有类及其依赖项。您已经提到您不想注册多个服务,但这很正常。如果它变大并且失控,有办法将其分解。