Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 网络生活方式与背景工作困惑_C#_Asp.net_.net_Simple Injector_Hangfire - Fatal编程技术网

C# 网络生活方式与背景工作困惑

C# 网络生活方式与背景工作困惑,c#,asp.net,.net,simple-injector,hangfire,C#,Asp.net,.net,Simple Injector,Hangfire,我的一个依赖项(DbContext)是使用WebApiRequestLifestyle范围注册的 现在,我的后台工作使用IoC,并且依赖于上面使用WebApiRequestLifestyle注册的服务。当Hangfire调用我为后台工作注册的方法时,我想知道这是如何工作的。由于不涉及web api,DbContext会被视为transistent对象吗 任何指导都会很好 以下是启动期间发生的初始化代码: public void Configuration(IAppBuilder app)

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

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

任何指导都会很好

以下是启动期间发生的初始化代码:

    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;
}
当Hangfire调用我为后台工作注册的方法时,我想知道这是如何工作的。由于不涉及web api,DbContext会被视为transistent对象吗

如前所述,Simple Injector永远不允许您解析活动范围之外的实例。这样DbContext既不会被解析为瞬态的,也不会被解析为单态的;当没有作用域时,Simple Injector将抛出异常

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

如果Hangfire作业在Windows服务中运行,则必须使用
ThreadScopedLifestyle
AsyncScopedLifestyle
。这些作用域需要显式启动

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

但是,您使用的是
Hangfire.SimpleInjector
集成库。此库实现了一个名为
SimpleInjectorJobActivator
的自定义
JobActivator
实现,此实现将在后台线程上为您创建一个启动范围。Hangfire将在该执行上下文范围的上下文中实际解析您的
Mailer
。因此,
MailNotificationHandler
中的
Mailer
构造函数参数实际上从未使用过;Hangfire将为您解决此类型的问题

webapirestLifestyle
AsyncScopedLifestyle
可以互换;
WebApiRequestLifestyle
在后台使用执行上下文作用域,而
simpleInjectorWebapidenceResolver
实际上启动了一个执行上下文作用域。因此,有趣的是,您的
WebApiRequestLifestyle
也可以用于后台操作(尽管它可能有点令人困惑)。因此,您的解决方案可以正常工作

但是,在MVC中运行时,这将不起作用,在这种情况下,您必须创建一个,例如:

var container = new Container();

container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
    new AsyncScopedLifestyle(),
    new WebRequestLifestyle());
您可以按如下方式注册DbContext:

container.Register<DbContext>(() => new DbContext(...), Lifestyle.Scoped);
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
依赖于这个新的抽象;不知道存在任何后台处理。现在靠近配置服务的部分,定义一个将调用转发到Hangfire的
iMail
代理:

// 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));
    }
}
//组成根目录的一部分
私人密封类HangfireBackgroundMailer:IMailer
{
public void SendFeedbackToSender(int feedbackId){
BackgroundJob.Enqueue(m=>m.SendFeedbackToSender(feedbackId));
}
public void SendFeedbackToManagement(int feedbackId){
BackgroundJob.Enqueue(m=>m.SendFeedbackToManagement(feedbackId));
}
}
这需要进行以下注册:

container.Register<IMailer, HangfireBackgroundMailer>(Lifestyle.Singleton);
container.Register<Mailer>(Lifestyle.Transient);
container.Register(lifesture.Singleton);
容器。寄存器(生活方式。瞬态);
这里我们将新的
HangfireBackgroundMailer
映射到
IMailer
抽象。这确保
BackgroundMailer
被注入到
MailNotificationHandler
中,而
Mailer
类在后台线程启动时由Hangfire解析。
Mailer
的注册是可选的,但还是可取的,因为它已成为根对象,并且具有依赖性,我们希望Simple Injector知道这种类型,以便它能够验证和诊断此注册


我希望您同意,从
MailNotificationHandler
的角度来看,应用程序现在更干净了。

hmm…我读过关于混合生活方式的文章,但现在我使用webapirequestlifety作为默认范围,当我在后台作业上设置断点时,它确实起作用。其实我也没想到。这有意义吗?我只是想澄清一下,我并没有试图访问http上下文或任何东西,只是访问使用WebApi作用域注册的DbContext依赖项。@Marco,WebApi请求生活方式实际上在后台使用ExecutionScopeLifedtyle,所以这也可以在后台线程上工作,只要显式启动执行上下文范围。然而,hangfire可能会将调用上下文从requedt移动到后台线程,但您需要启动一个新的scopeim simple injector,因此我认为您的上一个评论让我的大脑大为震动。:)因此,使用混合方法会更容易吗?非常感谢!它确实干净、优雅多了!我明天回到办公室后再给你一个时间。你是在使用
Hangfire.SimpleInjector
NuGet软件包并将'JobActivator.Current'设置为
SimpleInjector JobActivator
?@Steven是的,我很抱歉,我忘了在上面的代码中显示它。我刚刚加了。
// 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);