繁体   English   中英

在MVC 5.1中使用任务时出现Autofac global.asax错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM