Resolving Autofac components in background Tasks in ASP.NET

前端 未结 2 884
执笔经年
执笔经年 2020-12-19 10:20

Using Autofac in ASP.NET along with the ContainerDisposalModule, how can i support fire and forget calls that have component dependencies that need to be resolved? The prob

2条回答
  •  伪装坚强ぢ
    2020-12-19 10:43

    Answer posted by Alex adapted to current Autofac and MVC versions:

    • Use InstancePerRequest for a database context
    • Add ILifetimeScope as dependency to get to the container
    • SingleInstance ensures it's the root lifetime scope
    • Use HostingEnvironment.QueueBackgroundWorkItem to reliably run something in the background
    • Use MatchingScopeLifetimeTags.RequestLifetimeScopeTag to avoid having to know the tagname autofac uses for PerRequest lifetimes

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

    Gist: https://gist.github.com/janv8000/35e6250c8efc00288d21

    Global.asax.cs:

    protected void Application_Start() {
      //Other registrations
      builder.RegisterType();
      builder.RegisterType().As().InstancePerRequest();  //WebsiteContext is a EF DbContext
      builder.RegisterType().As().SingleInstance();
    }
    

    AsyncRunner.cs

    public interface IAsyncRunner
    {
        void Run(Action action);
    }
    
    public class AsyncRunner : IAsyncRunner
    {
        public ILifetimeScope LifetimeScope { get; set; }
    
        public AsyncRunner(ILifetimeScope lifetimeScope)
        {
            Guard.NotNull(() => lifetimeScope, lifetimeScope);
            LifetimeScope = lifetimeScope;
        }
    
        public void Run(Action 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();
                    action(service);
                }
            });
        }
    }
    

    Controller

    public Controller(IAsyncRunner asyncRunner)
    {
      Guard.NotNull(() => asyncRunner, asyncRunner);
      AsyncRunner = asyncRunner;
    }
    
    public ActionResult Index()
    {
      //Snip
      AsyncRunner.Run(listingService => listingService.RenderListing(listingGenerationArguments, Thread.CurrentThread.CurrentCulture));
      //Snip
    }
    

    ListingService

    public class ListingService : IListingService
    {
      public ListingService(IWebsiteContext context)
      {
        Guard.NotNull(() => context, context);
        Context = context;
      }
    }
    

提交回复
热议问题