[英]Autofac global.asax errors with using Tasks in MVC 5.1
我已经在global.asax.cs文件中使用Application事件设置了一系列任务,如下所示:
// Note: For instructions on enabling IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=301868
public class MvcApplication : System.Web.HttpApplication
{
private static IContainer ContainerGlobal;
private static ILogger Logger;
public ILifetimeScope Container
{
get { return (ILifetimeScope)HttpContext.Current.Items["_Container"]; }
set { HttpContext.Current.Items["_Container"] = value; }
}
protected void Application_Start()
{
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//configure the Autofac IoC container
var container = AutofacBuilder.Configure(Assembly.GetExecutingAssembly(),
new MvcModule(), new TaskModule());
// startup the logging
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase)
.Replace("file:\\", string.Empty);
var file = new FileInfo(path + @"\log4net.ui.config");
Logger = new Logger(MethodBase.GetCurrentMethod().DeclaringType, file);
var runAtInits = container.Resolve<IEnumerable<IRunAtInit>>();
if (runAtInits != null)
{
Logger.LogFormat(LogType.Debug, "Found {0} IRunAtInit instances",
runAtInits.Count());
foreach (var task in runAtInits)
{
task.Execute();
}
}
var runAtStartups = container.Resolve<IEnumerable<IRunAtStartup>>();
if (runAtStartups != null)
{
Logger.LogFormat(LogType.Debug, "Found {0} IRunAtStartup instances",
runAtStartups.Count());
foreach (var task in runAtStartups)
{
task.Execute();
}
}
ContainerGlobal = container;
}
public void Application_BeginRequest()
{
try
{
Container = ContainerGlobal.BeginLifetimeScope();
var runOnEachRequests =
Container.Resolve<IEnumerable<IRunOnEachRequest>>();
if (runOnEachRequests == null)
return;
Logger.LogFormat(LogType.Debug, "Found {0} IRunOnEachRequest instances",
runOnEachRequests.Count());
foreach (var task in runOnEachRequests)
{
task.Execute();
}
}
catch(Exception ex)
{
Logger.Log(LogType.Error, ex);
}
}
public void Application_Error()
{
try
{
var runOnErrors = Container.Resolve<IEnumerable<IRunOnError>>();
if (runOnErrors == null)
return;
Logger.LogFormat(LogType.Debug, "Found {0} IRunOnError instances",
runOnErrors.Count());
foreach (var task in runOnErrors)
{
task.Execute();
}
}
catch (Exception ex)
{
Logger.Log(LogType.Error, ex);
}
}
public void Application_EndRequest()
{
try
{
var runAfterEachRequests =
Container.Resolve<IEnumerable<IRunAfterEachRequest>>();
if (runAfterEachRequests == null)
return;
Logger.LogFormat(LogType.Debug, "Found {0} IRunAfterEachRequest instances",
runAfterEachRequests.Count());
foreach (var task in runAfterEachRequests)
{
task.Execute();
}
}
catch (Exception ex)
{
Logger.Log(LogType.Error, ex);
}
finally
{
if (Container != null)
{
Container.Dispose();
Container = null;
}
}
}
}
这是Matt Honeycut在这里讨论的:
https://github.com/MattHoneycutt/Fail-Tracker
当我们在整个应用程序中广泛使用Autofac时,我们已经使用Autofac而不是Structuremap来实现了它。
问题是,对于以下事件,我们会引发异常:Application_EndRequest,有时还会引发Application_BeginRequest。 在这两种情况下引发的异常是:
“从请求实例的范围中看不到带有匹配'AutofacWebRequest'的标记的范围。这通常表明SingleInstance()组件正在请求注册为HTTP请求的组件(或类似情况)。在网络集成下,始终从DependencyResolver.Current或ILifetimeScopeProvider.RequestLifetime请求依赖项,而不是从容器本身请求”
我们确保将ILifeScope用于我们的Container对象,而不是根Container对象。 但是,这不能解决错误。 其他人对我们还需要做什么有任何建议吗?
有关信息,上述对AutofacBuilder.Configure的调用将注册所有必需的库类型和模块,并通过调用Build方法从autofac返回根Container。
谢谢
PS我们正在使用: Visual Studio 2013,MVC 5.1 Autofac 3.3
该错误消息几乎说明了一切,但更具体地说,正在发生以下一种或多种情况:
InstancePerHttpRequest
InstancePerHttpRequest
DependencyResolver.Current
。 Autofac依赖关系解析器需要Web请求上下文才能工作。 您可以在此处的答案中了解更多有关此信息: Autofac-由于HttpContext不可用,因此无法创建请求生存期范围-由于异步代码?
应用开始/结束没有正在运行的网络请求。 它们不在请求管道中。
完成您的注册(似乎在AutofacBuilder.Configure
),然后检查哪些是InstancePerHttpRequest
。 以这种方式错误地注册了处理程序执行期间所需的某些内容,因此当未找到Web请求范围时-boom 。 而且,这可能不只是一件事-可能是所有处理程序都正确注册,但是处理程序的依赖项之一是InstancePerHttpRequest
注册。
如果发现问题,并且不想切换为将其注册为SingleInstance
,请考虑将注册切换为InstancePerLifetimeScope
。 除非您的应用程序为工作单位或其他东西创建了一堆生命周期范围,否则InstancePerLifetimeScope
行为就像InstancePerHttpRequest
一样,但是在没有Web请求的情况下可以正确解析。
也就是说,我建议将任务执行包装在生存期范围内,以便清理内存:
using(var scope = container.BeginLifetimeScope())
{
// Resolve from a scope.
var runAtStartups = scope.Resolve<IEnumerable<IRunAtStartup>>();
// Do the run, etc.
}
最后,需要注意的是:我看到您在BeginRequest
事件中自己手动生成某种请求生存期范围。 我不确定这是否重要,但是您在其中创建的作用域将不会包含Autofac实际使用的请求生存期作用域 。 它仅用于您的组件,不适用于InstancePerHttpRequest
注册的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.