【问题标题】:Lifetime scope with autofac, webforms and ServiceLocator使用 autofac、webforms 和 ServiceLocator 的生命周期范围
【发布时间】:2014-09-19 21:35:46
【问题描述】:

在旧的 Asp.NET webforms 应用程序中,我尝试注入一些 IOC。

我不会详细介绍,但对于这个,我认为 ServiceLocator 是一个很好的工具。 我知道服务定位器是一种反模式;o)

根据文档https://github.com/autofac/Autofac/wiki/Common-Service-Locator,ServiceLocator 配置如下:

var container = builder.Build();
var csl = new AutofacServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => csl);

问题是 LoacatorProvider 是用根容器设置的。所以,生命周期管理是不活跃的。

我正在想办法解决这个问题

因为ServiceLocator.SetLocatorProvider 将委托作为参数,并且因为每次调用ServiceLocator.Current 都会调用此委托,所以为什么不为每个请求提供一个 AutofacServiceLocator 实例。

public class Global : HttpApplication, IContainerProviderAccessor
{
    // Provider that holds the application container.
    static IContainerProvider _containerProvider;

    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        _containerProvider = new ContainerProvider(AutoFacBootstrapper.CreateContainer());

        ServiceLocator.SetLocatorProvider(() =>
        {
            AutofacServiceLocator asl = HttpContext.Current.Items["AutofacServiceLocator"] as AutofacServiceLocator;
            if (asl == null)
            {
                var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
                var cp = cpa.ContainerProvider.RequestLifetime;
                asl = new AutofacServiceLocator(cp);

                HttpContext.Current.Items["AutofacServiceLocator"] = asl;
            }
            return asl;
        });
    }

    public IContainerProvider ContainerProvider
    {
        get { return _containerProvider; }
    }
}

此代码似乎有效。 IDisposable 对象在请求结束时被释放。 InstancePerRequest配置没问题。

此实现是否存在任何问题(性能、内存...)?

【问题讨论】:

  • 你还在用这种方法吗?我们遇到了类似的问题。
  • 事实上,我计划在一个尚未准备好接受纯 ioc 糖的遗留网络表单应用程序中使用这种方法。我只是问这样走行不行。
  • 猜这是一个不可能的问题;)我们做了一些非常相似的事情 - 将定位器提供程序设置为从根容器解析服务的 func,然后根据子范围提供适当的服务定位器。它尚未投入生产,但在分析时,它似乎解决了我们看到的内存泄漏问题(无法使用任何开箱即用的解决方案,因为我们需要在同一应用程序中对 WCF 和 MVC 进行生命周期管理)

标签: asp.net webforms autofac lifetime


【解决方案1】:

如果它对其他人有帮助,以下是我将其作为请求处理程序实现的方式。

这是我的 Startup.cs:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();

        // ...
        IContainer container = ConfigureAutofac(config);

        // This should be the first middleware added to the IAppBuilder.
        app.UseAutofacMiddleware(container);

        // Make sure the Autofac lifetime scope is passed to Web API.
        app.UseAutofacWebApi(config);

        app.UseWebApi(config);           

        config.MessageHandlers.Add(new ServiceLocatorHandler());
    }
}

我会在下面显示ServiceLocatorHandler.cs

为了完整起见,这是我的ConfigureAutofac 函数:

    private IContainer ConfigureAutofac(HttpConfiguration config)
    {
        var builder = new ContainerBuilder();
        var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
        builder.RegisterAssemblyModules(assemblies.ToArray());

        // Register Web API classes
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        builder.RegisterWebApiFilterProvider(config);
        builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

        // Register the modules
        // ...

        // Create the container
        var container = builder.Build();

        // Hook up the Web API dependency resolver
        var resolver = new AutofacWebApiDependencyResolver(container);
        config.DependencyResolver = resolver;

        // ...
        ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));

        return container;
    }

最后,这是处理程序:

public class ServiceLocatorHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var properties = request.Properties;
        var scope = properties["MS_DependencyScope"];
        AutofacWebApiDependencyScope dependency_scope = scope as AutofacWebApiDependencyScope;
        if (dependency_scope != null && dependency_scope.LifetimeScope != null)
        {
            AutofacWebApiDependencyResolver resolver = new AutofacWebApiDependencyResolver(dependency_scope.LifetimeScope);
            AutofacServiceLocator asl = new AutofacServiceLocator(resolver.Container);
            ServiceLocator.SetLocatorProvider(() => asl);
        }
        return base.SendAsync(request, cancellationToken);
    }
}

在我的用例中,我有一个第 3 方库,它使用 IoC 通过存储库模式解析 DBContext 实现。

这个库在使用其他 DI 容器的其他环境中使用,当使用默认的 AutofacServiceLocator 根设置时,我会看到旧数据的 EF 缓存问题或写入失败,因为将在对象添加之间创建新的上下文并提交。

非常感谢 OP 帮助我们解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多