在 ASP.NET 中使用 Autofac 和 ContainerDisposalModule,我如何支持具有需要解决的组件依赖项的触发和忘记调用?我遇到的问题是 ASP.NET 请求在任务运行之前完成并处理了请求的生命周期范围,因此任何需要在新线程中解析的组件都会失败,并显示消息“无法解析实例并且嵌套的生命周期不能从这个 LifetimeScope 创建,因为它已经被释放了”。在 ASP.NET 中使用 Autofac 支持触发和忘记呼叫的最佳方法是什么?我不想延迟执行某些可以在后台线程上完成的任务的请求。
问问题
5524 次
2 回答
8
Alex 发布的答案适用于当前的 Autofac 和 MVC 版本:
- 用于
InstancePerRequest
数据库上下文 - 添加
ILifetimeScope
为依赖项以获取容器 SingleInstance
确保它是根生命周期范围- 用于
HostingEnvironment.QueueBackgroundWorkItem
在后台可靠地运行某些东西 - 用于
MatchingScopeLifetimeTags.RequestLifetimeScopeTag
避免必须知道 autofac 用于 PerRequest 生命周期的标记名
https://groups.google.com/forum/#!topic/autofac/gJYDDls981A https://groups.google.com/forum/#!topic/autofac/yGQWjVbPYGM
要点:https ://gist.github.com/janv8000/35e6250c8efc00288d21
全球.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();
}
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);
}
});
}
}
控制器
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
}
上市服务
public class ListingService : IListingService
{
public ListingService(IWebsiteContext context)
{
Guard.NotNull(() => context, context);
Context = context;
}
}
于 2015-01-12T13:49:36.443 回答
4
您需要创建一个独立于请求生命周期范围的新生命周期范围。下面的博客文章显示了如何使用 MVC 执行此操作的示例,但相同的概念可以应用于 WebForms。
http://aboutcode.net/2010/11/01/start-background-tasks-from-mvc-actions-using-autofac.html
如果您需要确保在请求完成后确定执行异步工作,那么这不是一个好方法。在这种情况下,我建议在请求期间将消息发布到队列中,以允许单独的进程获取并执行工作。
于 2012-08-12T14:07:52.200 回答