在ASP.NET中的后台任务中解决Autofac组件

use*_*480 4 asp.net autofac fire-and-forget

将ASP.NET中的Autofac与ContainerDisposalModule一起使用,我如何才能支持具有需要解决的组件依赖性的调用并忘记调用?我遇到的问题是ASP.NET请求在任务运行之前完成并处理了请求的生存期范围,因此任何需要在新线程中解析的组件都会失败,并显示消息“实例无法解析”并且无法从此LifetimeScope创建嵌套的生存期,因为它已经被处理掉了”。在ASP.NET中使用Autofac支持发火和忘记通话的最佳方法是什么?我不想延迟执行可以在后台线程上完成的某些任务的请求。

jan*_*000 7

Alex发布的答案适应了当前的Autofac和MVC版本:

  • 使用InstancePerRequest一个数据库上下文
  • 添加ILifetimeScope为依赖项以获取容器
  • SingleInstance 确保它是根生命周期范围
  • 使用HostingEnvironment.QueueBackgroundWorkItem可靠地在后台运行的东西
  • 使用MatchingScopeLifetimeTags.RequestLifetimeScopeTag以避免必须知道PerRequest寿命标记名autofac用途

https://groups.google.com/forum/#!topic/autofac/gJYDDls981A https://groups.google.com/forum/#!topic/autofac/yGQWjVbPYGM

要点:https : //gist.github.com/janv8000/35e6250c8efc00288d21

Global.asax.cs:

protected void Application_Start() {
  //Other registrations
  builder.RegisterType<ListingService>();
  builder.RegisterType<WebsiteContext>().As<IWebsiteContext>().InstancePerRequest();  //WebsiteContext is a EF DbContext
  builder.RegisterType<AsyncRunner>().As<IAsyncRunner>().SingleInstance();
}
Run Code Online (Sandbox Code Playgroud)

AsyncRunner.cs

public interface IAsyncRunner
{
    void Run<T>(Action<T> action);
}

public class AsyncRunner : IAsyncRunner
{
    public ILifetimeScope LifetimeScope { get; set; }

    public AsyncRunner(ILifetimeScope lifetimeScope)
    {
        Guard.NotNull(() => lifetimeScope, lifetimeScope);
        LifetimeScope = lifetimeScope;
    }

    public void Run<T>(Action<T> action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(ct =>
        {
            // Create a nested container which will use the same dependency
            // registrations as set for HTTP request scopes.
            using (var container = LifetimeScope.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag))
            {
                var service = container.Resolve<T>();
                action(service);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

控制者

public Controller(IAsyncRunner asyncRunner)
{
  Guard.NotNull(() => asyncRunner, asyncRunner);
  AsyncRunner = asyncRunner;
}

public ActionResult Index()
{
  //Snip
  AsyncRunner.Run<ListingService>(listingService => listingService.RenderListing(listingGenerationArguments, Thread.CurrentThread.CurrentCulture));
  //Snip
}
Run Code Online (Sandbox Code Playgroud)

ListingService

public class ListingService : IListingService
{
  public ListingService(IWebsiteContext context)
  {
    Guard.NotNull(() => context, context);
    Context = context;
  }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*ves 5

您需要创建一个独立于请求生命周期范围的新生命周期范围。下面的博客文章展示了如何使用 MVC 执行此操作的示例,但相同的概念也可以应用于 WebForms。

http://aboutcode.net/2010/11/01/start-background-tasks-from-mvc-actions-using-autofac.html

如果您需要确保在请求完成后明确执行异步工作,那么这不是一个好方法。在这种情况下,我建议在请求期间将消息发布到队列中,以允许单独的进程接收该消息并执行工作。