使用autofac,webforms和ServiceLocator的生命周期范围

Pas*_*mey 6 asp.net webforms lifetime autofac

在传统的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);
Run Code Online (Sandbox Code Playgroud)

问题是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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这段代码似乎有效.IDisposable对象在请求结束时处理.InstancePerRequest配置还可以.

这个实现有什么问题(表演,记忆......)吗?

use*_*608 0

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

这是我的 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

下面我就展示一下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;
    }
Run Code Online (Sandbox Code Playgroud)

最后,这是处理程序:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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