可以将其他数据作为常规方法参数传递给后台作业。我会再次写下下面的一行(希望没有打扰到你):
BackgroundJob.Enqueue(() => Console.WriteLine("Hello, {0}!", "world"));
与常规方法调用一样,这些参数在后台作业执行期间将可用于Console.WriteLine方法。但由于它们是通过进程边界编组的,所以它们是串行化的。
很棒的Newtonsoft.Json包用于将参数序列化为Json字符串(从1.1.0版开始)。因此,几乎可以使用任何类型作为参数;包括数组、集合和自定义对象。有关详细信息,请参阅相应的文档。
不支持引用参数。不能通过引用向参数传递参数–不支持ref和out关键字。
由于参数是序列化的,请仔细考虑它们的值,因为它们可能会破坏作业存储。大多数时候,将具体值存储在应用程序数据库中并仅将其标识符传递给后台作业会更有效。
请记住,后台作业可能在排队几天或几周后处理。如果你使用的数据可能会在你的论点中发生变化,那么它可能会过时——数据库记录可能会被删除,文章的文本可能会被更改,等等。计划这些变化,并相应地设计你的后台工作。
传递依赖项
在几乎每项工作中,您都希望使用应用程序的其他类来执行不同的工作,并保持代码干净简单。让我们将这些类称为依赖项。如何将这些依赖项传递给将在后台调用的方法?
当您在后台调用静态方法时,您仅限于应用程序的静态上下文,这要求您使用以下获取依赖项的模式:
- 通过新运算符手动实例化依赖关系
- 本地服务
- 抽象工厂或构建者
- 单例
然而,所有这些模式都使应用程序的单元可测试性方面非常复杂。为了解决这个问题,Hangfire允许您在后台调用实例方法。假设您有以下类,它使用某种DbContext访问数据库,使用EmailService发送电子邮件。
public class EmailSender
{
public void Send(int userId, string message)
{
var dbContext = new DbContext();
var emailService = new EmailService();
// Some processing logic
}
}
要在后台调用Send方法,请使用以下Enqueue方法的重写(BackgroundJob类的其他方法也提供此类重载):
BackgroundJob.Enqueue<EmailSender>(x => x.Send(13, "Hello!"));
当工作程序确定需要调用实例方法时,它首先使用当前JobActivator类实例创建给定类的实例。默认情况下,它使用Activator.CreateInstance方法,该方法可以使用其默认构造函数创建类的实例,因此让我们添加它:
public class EmailSender
{
private IDbContext _dbContext;
private IEmailService _emailService;
public EmailSender()
{
_dbContext = new DbContext();
_emailService = new EmailService();
}
// ...
}
如果您希望类准备好进行单元测试,请考虑添加构造函数重载,因为默认激活器无法创建没有默认构造函数的类的实例:
public class EmailSender
{
// ...
public EmailSender()
: this(new DbContext(), new EmailService())
{
}
internal EmailSender(IDbContext dbContext, IEmailService emailService)
{
_dbContext = dbContext;
_emailService = emailService;
}
}
如果您使用IoC容器,例如Autofac、Ninject、SimpleInjector等,则可以删除默认构造函数。要了解如何做到这一点,请转到下一节。