【问题标题】:Autofac and the HttpContextAutofac 和 HttpContext
【发布时间】:2017-07-28 08:50:50
【问题描述】:

我有很多需要访问当前用户的服务。 我设置了一个绑定到当前 HttpContext 的 PrincipalProvider,我还为每个请求注册了它,这样一旦实例化,它就永远不会丢失上下文。 它看起来像这样:

public class PrincipalProvider : IPrincipalProvider
{

    // Readonly fields
    private readonly HttpContext _current;

    /// <summary>
    /// Default constructor
    /// </summary>
    public PrincipalProvider()
    {
        _current = HttpContext.Current;
    }

    /// <summary>
    /// Gets the current user
    /// </summary>
    public IPrincipal User => _current?.User;
}

我是这样绑定的:

builder.RegisterType<PrincipalProvider>().As<IPrincipalProvider>().InstancePerRequest();

现在,任何注入了它的服务都应该暴露用户。我遇到的问题很简单。如果我有一个这样设置的控制器:

public OrdersController(IOrderProvider provider)
{
    _provider = provider;
}

IOrderProvider 将 IPrincipleProvider 延迟注入其中,因此在这种情况下,用户可用,因为父服务是在 Controller 上创建的。问题是它是否没有注入到服务中,而是用于注入到其中的另一个服务。 例如,我有这个控制器:

public UsersController(IUserProvider provider, IAdvancedEncryptionStandardProvider encyptionProvider, IPhotoManager photoManager)
{
    _userProvider = provider;
    _encryptionProvider = encyptionProvider;
    _photoManager = photoManager;
}

IUserProvider 没有注入 IPrincipalProvider,但它确实有另一个服务:

public TroposSessionRequest(CormarConfig config, IAdvancedEncryptionStandardProvider encryptionProvider, Lazy<IPrincipalProvider> principalProvider)
{
    _config = config;
    _encryptionProvider = encryptionProvider;
    _principalProvider = principalProvider;
}

这里的问题是,当创建 TroposSessionRequest 时,HttpContext 不可用,因此为空。 我希望有一种方法可以在上下文可用时实例化 IPrincipleProvider,然后在整个请求中保留它。 我们可以为每个请求执行此操作,因为几乎总是需要 PrincipalProvider。

有人知道怎么做吗?

【问题讨论】:

    标签: c# asp.net-web-api2 autofac


    【解决方案1】:

    解决此问题的最简单方法是在您的User 访问器中访问HttpContext.Current:

    public IPrincipal User => HttpContext.Current?.User;
    

    如果您担心可测试性,可以mock HttpContext.Current.User relatively easily。

    如果您打算使用 DI 解决它,您可以在 IHttpContextAccessor 依赖项后面抽象出 HttpContext(但由于您仍然依赖于 HttpContext 类型,因此您仍然处于同一条船上测试)。

    public class PrincipalProvider : IPrincipalProvider
    {
    
        // Readonly fields
        private readonly IHttpContextAccessor _httpContextAccessor;
    
        /// <summary>
        /// Default constructor
        /// </summary>
        public PrincipalProvider(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
    
        /// <summary>
        /// Gets the current user
        /// </summary>
        public IPrincipal User => _httpContextAccessor.HttpContext?.User;
    }
    

    【讨论】:

    • 在我看来,您的“解决方法”根本不是解决方法。它实际上是 the 解决方案,因为您应该 prevent having runtime data in the object graph during construction.
    • 在哪里可以访问此 IHttpContextAccessor?这是仅在核心中可用的东西吗?我没有使用 .net 核心 :(
    • 我的意思是你自己定义。
    猜你喜欢
    • 2014-12-18
    • 2017-09-26
    • 2011-12-23
    • 1970-01-01
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    相关资源
    最近更新 更多