3

我目前正在使用 AutoFac 作为我们的 ServiceStack Web 服务应用程序的 DI 容器。我可以配置接线和所有内容,但是在阅读了有关 Scopes 的部分之后,我不知道在注册我的组件时最好使用哪个范围。在我们的特殊情况下,我认为 PerHttpRequest 范围是可以的,因为(如果我错了,请纠正我)我想在请求结束后立即处理依赖项。

我的问题是,如何在容器中进行设置?我似乎无法在 autofac 包含的方法中找到“PerHttpRequest”生命周期范围。我也不确定 ServiceStack 是否会在幕后为我做某种自动化。

我在 .Net 4 上的 ServiceStack 3.9.35 上使用 Autofac 3.0.1(作为常规 ASP 主机运行,而不是 MVC)。我还将此处描述的类用作 IContainer 适配器。

4

4 回答 4

5

我想避免依赖 MVC 的开销,所以第一个答案对我来说不太适用。

相反,我使用 Funq 注册了 PerRequest ILifetimeScope,并在解析依赖项之前解析了 ConatinerAdaptor 中的 ILifetimeScope。

public class AutofacLifetimeScopeIocAdapter : IContainerAdapter
{
    private readonly Container _requestContainer;

    public AutofacLifetimeScopeIocAdapter(Funq.Container requestContainer)
    {
        _requestContainer = requestContainer;
    }


    public T Resolve<T>()
    {
        var currentContainer = _requestContainer.Resolve<ILifetimeScope>();

        return currentContainer.Resolve<T>();
    }

    public T TryResolve<T>()
    {
        var currentContainer = _requestContainer.Resolve<ILifetimeScope>();

        T result;

        if (currentContainer.TryResolve<T>(out result))
        {
            return result;
        }

        return default(T);
    }

}

然后用这个初始化

_autofacContainerRoot = builder.Build();
        IContainerAdapter adapter = new AutofacLifetimeScopeIocAdapter(container);

        container.Register<ILifetimeScope>((c) => _autofacContainerRoot.BeginLifetimeScope())
            .ReusedWithin(ReuseScope.Request);

        container.Adapter = adapter;

然后清理

public override void OnEndRequest()
    {
        var currentContainer = _container.Resolve<ILifetimeScope>();
        currentContainer.Dispose();

        base.OnEndRequest();
    } 

这似乎符合 Autofac 的要求——SingleInstance、InstancePerDependency,现在是 perRequest 的 InstancePerLifetimeScope。

HostContext.Instance.Items 集合上的神话响应可能用于消除对

var currentContainer = _container.Resolve<ILifetimeScope>();

分辨率,这应该会提高性能。

于 2013-11-11T12:34:30.750 回答
4

我想我已经弄清楚了如何完成这项工作(使用 Autofac 2.6,我现在坚持使用它。)它涉及使用以下适配器和 Autofac.Mvc3 包:

public class AutofacIocAdapter : IContainerAdapter
{
    private readonly IContainer _autofacRootContainer;
    private readonly Container _funqContainer;

    public AutofacIocAdapter(IContainer autofacRootContainer, Container funqContainer)
    {
        // Register a RequestLifetimeScopeProvider (from Autofac.Integration.Mvc) with Funq
        var lifetimeScopeProvider = new RequestLifetimeScopeProvider(autofacRootContainer,null);
        funqContainer.Register<ILifetimeScopeProvider>(x => lifetimeScopeProvider);
        // Store the autofac application (root) container, and the funq container for later use
        _autofacRootContainer = autofacRootContainer;
        _funqContainer = funqContainer;
    }

    public T Resolve<T>()
    {           
        return ActiveScope.Resolve<T>();
    }

    public T TryResolve<T>()
    {
        T result;
        if (ActiveScope.TryResolve(out result))
        {
            return result;
        }
        return default(T);
    }

    private ILifetimeScope ActiveScope
    {
        get
        {
            // If there is an active HttpContext, retrieve the lifetime scope by resolving
            // the ILifetimeScopeProvider from Funq.  Otherwise, use the application (root) container.
            return HttpContext.Current == null
                        ? _autofacRootContainer
                        : _funqContainer.Resolve<ILifetimeScopeProvider>().GetLifetimeScope();
        }
    }
}

实施步骤:

  1. 将 Autofac.Mvc3 NuGet 包添加到您的 Web 项目(注意: 您的项目不使用 MVC并不重要。解决方案可能与 Autofac 3 略有不同,它不能使用 Mvc3 集成。)
  2. 按照ServiceStack IoC页面为 Autofac 连接自定义 IContainerAdapter,使用以下实现
于 2013-03-15T15:32:21.820 回答
2

注意ServiceStack 的IOC 中的RequestScope只指ServiceStack 内置的Funq IOC。

要在另一个 IOC 容器(如 AutoFac)中使用 RequestScope,您通常需要在请求结束时通知 AutoFac,以便它可以清理其所有请求范围的实例。为此,ServiceStack 提供了AppHostBase.OnEndRequest()可以覆盖的钩子,以便在每个请求结束时执行自定义逻辑。

我不熟悉 AutoFac 的自定义生命周期范围的工作原理,但可以在以下位置找到更多详细信息:

其他可能对管理 ServiceStack 中的实例有用的信息是,放入HostContext.Instance.Items字典或一次性添加 的每个实例都会在每个请求结束时自动HostContext.Instance.TrackDisposable释放。

于 2013-02-12T16:43:31.477 回答
2

2015-11-25 更新:我通过使用全局请求和响应过滤器更改了实现。我将 ServiceStack V3 和 V4 解决方案都放入了这个存储库,这两个版本都可以作为nuget 包使用。

我通过在 Application_BeginRequest 中打开一个新范围并在 Application_EndRequest 中进行处理来解决了这个问题。在容器适配器中,我检查这个范围是否存在并使用它,如果不存在,我使用容器。这允许使用 .InstancePerRequest() 注册范围。

在这里用要点描述。

于 2015-04-15T09:34:28.427 回答