gpt4 book ai didi

c# - WebApiRequestLifestyle 和 BackgroundJob 混淆

转载 作者:太空狗 更新时间:2023-10-30 01:01:46 29 4
gpt4 key购买 nike

我的依赖项之一(DbContext)是使用 WebApiRequestLifestyle 范围注册的。

现在,我的后台作业使用 IoC 并依赖于上面使用 WebApiRequestLifestyle 注册的服务。我想知道当 Hangfire 调用我为后台作业注册的方法时这是如何工作的。由于不涉及 Web api,DbContext 是否会被视为 transient 对象?

任何指导都会很棒!

这是我在启动期间发生的初始化代码:

    public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();

var container = SimpleInjectorWebApiInitializer.Initialize(httpConfig);

var config = (IConfigurationProvider)httpConfig.DependencyResolver
.GetService(typeof(IConfigurationProvider));

ConfigureJwt(app, config);
ConfigureWebApi(app, httpConfig, config);
ConfigureHangfire(app, container);
}
private void ConfigureHangfire(IAppBuilder app, Container container)
{
Hangfire.GlobalConfiguration.Configuration
.UseSqlServerStorage("Hangfire");

Hangfire.GlobalConfiguration.Configuration
.UseActivator(new SimpleInjectorJobActivator(container));

app.UseHangfireDashboard();
app.UseHangfireServer();
}

public static Container Initialize(HttpConfiguration config)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

InitializeContainer(container);

container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterWebApiControllers(config);
container.RegisterMvcIntegratedFilterProvider();

container.Register<Mailer>(Lifestyle.Scoped);
container.Register<PortalContext>(Lifestyle.Scoped);
container.RegisterSingleton<TemplateProvider, TemplateProvider>();

container.Verify();

DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

return container;
}

这是我启动后台工作的代码:
public class MailNotificationHandler : IAsyncNotificationHandler<FeedbackCreated>
{
private readonly Mailer mailer;

public MailNotificationHandler(Mailer mailer)
{
this.mailer = mailer;
}

public Task Handle(FeedbackCreated notification)
{
BackgroundJob.Enqueue<Mailer>(x => x.SendFeedbackToSender(notification.FeedbackId));
BackgroundJob.Enqueue<Mailer>(x => x.SendFeedbackToManagement(notification.FeedbackId));

return Task.FromResult(0);
}
}

最后是在后台线程上运行的代码:
public class Mailer
{
private readonly PortalContext dbContext;
private readonly TemplateProvider templateProvider;

public Mailer(PortalContext dbContext, TemplateProvider templateProvider)
{
this.dbContext = dbContext;
this.templateProvider = templateProvider;
}

public void SendFeedbackToSender(int feedbackId)
{
Feedback feedback = dbContext.Feedbacks.Find(feedbackId);

Send(TemplateType.FeedbackSender, new { Name = feedback.CreateUserId });
}

public void SendFeedbackToManagement(int feedbackId)
{
Feedback feedback = dbContext.Feedbacks.Find(feedbackId);

Send(TemplateType.FeedbackManagement, new { Name = feedback.CreateUserId });
}

public void Send(TemplateType templateType, object model)
{
MailMessage msg = templateProvider.Get(templateType, model).ToMailMessage();

using (var client = new SmtpClient())
{
client.Send(msg);
}
}
}

最佳答案

I'm wondering how this works when Hangfire calls the method i registered for the background job. Will the DbContext be treated like a transistent object since the web api is not involved?



作为 design decisions描述,Simple Injector 永远不会允许您解析事件范围之外的实例。这样 DbContext 就不会被解析为 transient 或单例;当没有作用域时,Simple Injector 会抛出异常。

每种应用程序类型都需要自己的范围生活方式。 Web API 需要 AsyncScopedLifestyle (在以前的版本中 WebApiRequestLifestyle ),WCF 和 WcfOperationLifestyle和 MVC WebRequestLifestyle .对于 Windows 服务,您通常会使用 AsyncScopedLifestyle .

如果您的 Hangfire 作业在 Windows 服务中运行,则必须使用 ThreadScopedLifestyleAsyncScopedLifestyle .这些范围需要明确的开始。

在 Web(或 Web API)应用程序的后台线程上运行作业时,无法访问所需的上下文,这意味着如果您尝试这样做,Simple Injector 将抛出异常。

但是,您正在使用 Hangfire.SimpleInjector集成库。这个库实现了一个自定义 JobActivator实现称为 SimpleInjectorJobActivator这个实现将创建一个 Scope在后台线程上为您服务。 Hangfire 实际上会解决您的 Mailer在此执行上下文范围的上下文中。所以 Mailer MailNotificationHandler 中的构造函数参数实际上从未使用过; Hangfire 将为您解决此类型。
WebApiRequestLifestyleAsyncScopedLifestyle可以互换; WebApiRequestLifestyle在后台使用执行上下文范围和 SimpleInjectorWebApiDependencyResolver实际上启动了一个执行上下文范围。所以有趣的是你的 WebApiRequestLifestyle也可以用于后台操作(尽管它可能有点困惑)。因此,您的解决方案可以正常工作。

但是,在 MVC 中运行时,这将不起作用,在这种情况下,您必须创建一个 Hybrid lifestyle , 例如:
var container = new Container();

container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
new AsyncScopedLifestyle(),
new WebRequestLifestyle());

您可以按如下方式注册您的 DbContext:
container.Register<DbContext>(() => new DbContext(...), Lifestyle.Scoped);

如果您不介意,这里有一些关于您的应用程序设计的反馈。

防止让应用程序代码,例如您的 MailNotificationHandler ,从直接依赖于外部库(例如 Hangfire)。这直接违反了依赖倒置原则,使您的应用程序代码很难测试和维护。相反,仅让您的 Composition Root(连接依赖项的地方)依赖于 Hangfire。在您的情况下,解决方案非常简单,我什至会说令人愉快,它看起来如下:
public interface IMailer
{
void SendFeedbackToSender(int feedbackId);
void SendFeedbackToManagement(int feedbackId);
}

public class MailNotificationHandler : IAsyncNotificationHandler<FeedbackCreated>
{
private readonly IMailer mailer;

public MailNotificationHandler(IMailer mailer)
{
this.mailer = mailer;
}

public Task Handle(FeedbackCreated notification)
{
this.mailer.SendFeedbackToSender(notification.FeedbackId));
this.mailer.SendFeedbackToManagement(notification.FeedbackId));

return Task.FromResult(0);
}
}

在这里我们添加了一个新的 IMailer抽象并制作了 MailNotificationHandler依赖于这个新的抽象;不知道任何后台处理的存在。现在靠近您配置服务的部分,定义 IMailer将调用转发到 Hangfire 的代理:
// Part of your composition root
private sealed class HangfireBackgroundMailer : IMailer
{
public void SendFeedbackToSender(int feedbackId) {
BackgroundJob.Enqueue<Mailer>(m => m.SendFeedbackToSender(feedbackId));
}

public void SendFeedbackToManagement(int feedbackId) {
BackgroundJob.Enqueue<Mailer>(m => m.SendFeedbackToManagement(feedbackId));
}
}

这需要以下注册:
container.Register<IMailer, HangfireBackgroundMailer>(Lifestyle.Singleton);
container.Register<Mailer>(Lifestyle.Transient);

在这里我们映射新的 HangfireBackgroundMailerIMailer抽象。这确保了 BackgroundMailer注入(inject)您的 MailNotificationHandler ,而 Mailer当后台线程启动时,类由 Hangfire 解析。注册 Mailer是可选的,但建议使用,因为它已成为根对象,并且由于它具有依赖关系,因此我们希望 Simple Injector 知道此类型以允许它验证和诊断此注册。

我希望你同意 MailNotificationHandler 的观点,应用程序现在干净多了。

关于c# - WebApiRequestLifestyle 和 BackgroundJob 混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36918995/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com