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

时间:2014-07-28 16:19:52

标签: asp.net webforms autofac lifetime

在传统的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配置正常。

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

1 个答案:

答案 0 :(得分:0)

如果它可以帮助其他人,请按照以下方式将其实现为请求处理程序。

这是我的Startup.cs:

Template.series72.onRendered(function(){
   $('.download').attr({
        download: '',
        target: '_blank', 
        href  : '../pdfs/sizing-diagram-series-72.pdf'
   });
});

我将在下面显示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;
    }

在我的用例中,我有一个第三方库,它使用IoC通过存储库模式解析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); } } 实现。

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

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