构造函数中的 HttpContext null

问题描述 投票:0回答:2

我有一个 UserContext 服务,我将在其中放置一些基本功能(“

IsAuthenticated
GetUser
等...)

为了做到这一点,我需要将

HTTPContext
从我的 WebAPI 控制器传递到我的类库服务。

实际上,

HttpContext
在Web API控制器中始终是
null

有人有办法解决我的问题吗? 有没有更好的方法来实现它。

Web API 用户控制器

[Route("api/[controller]")]
[Authorize]
public class UserController : Controller
{
    private readonly IUserContextServices _userContextServices;
    private readonly User loggedUser;

    public UserController()
    {
       //HttpContext ALWAYS NULL
        _userContextServices = new UserContextService(HttpContext);
    }
 }  

用户上下文服务

namespace MyProj.Services
{
    public interface IUserContextServices
    {
        UserContext GetUserContext();
        bool IsUserAuthenticated();
    }

    public class UserContextService : IUserContextServices
    {
        private readonly HttpContext _context;
        private UserContext _userContext;
        public UserContextService(HttpContext context)
        {
            _context = context;
            InitUserContext();
        }

        private IEnumerable<Claim> GetUserClaims()
        {
            if (IsUserAuthenticated())
            {
                return _context.User.Claims;
            }
            return null;
        }

        private void InitUserContext()
        {
            if (IsUserAuthenticated())
            {
                var claims = GetUserClaims();
                _userContext = new UserContext();
                _userContext.Email = claims.First(p => p.Type == "email").Value;
                _userContext.AspNetUserID = claims.First(p => p.Type == "sub").Value;
            }
        }

        public UserContext GetUserContext()
        {
            return _userContext;
        }

        public bool IsUserAuthenticated()
        {
            return _context.User != null && _context.User.Identity != null && _context.User.Identity.IsAuthenticated;
        }
    }
}
c# dependency-injection asp.net-core asp.net-core-webapi
2个回答
17
投票
当调用Controller的构造函数时,

HttpContext
不可用。您将必须重新设计代码才能稍后在调用流程中获取上下文。这就是
IHttpContextAccessor
的用途。

public interface IHttpContextAccessor {
    HttpContext HttpContext { get; }
}

将其注入到服务中,然后根据需要访问上下文。

public class UserContextService : IUserContextServices {
    private readonly IHttpContextAccessor contextAccessor;
    private UserContext _userContext;
    public UserContextService(IHttpContextAccessor accessor) {
        contextAccessor = accessor;
    }

    private HttpContext Context {
        get {
            return contextAccessor.HttpContext;
        }
    }

    public UserContext GetUserContext() {
        if (_userContext == null && IsUserAuthenticated()) {
            var claims = Context?.User?.Claims;
            _userContext = new UserContext() {
                Email = claims.First(p => p.Type == "email").Value,
                AspNetUserID = claims.First(p => p.Type == "sub").Value
            };
        }
        return _userContext;
    }

    public bool IsUserAuthenticated() {
        return Context?.User?.Identity?.IsAuthenticated;
    }
}

将服务抽象注入到控制器中

[Route("api/[controller]")]
[Authorize]
public class UserController : Controller {
    private readonly IUserContextServices _userContextServices;
    private readonly User loggedUser;

    public UserController(IUserContextServices userContextServices) {
        _userContextServices = userContextServices;
    }

    //...
}

IHttpContextAccessor
默认情况下不在服务集合中,因此您需要手动将其添加到
Startup.ConfigureServices
中才能注入它:

services.AddHttpContextAccessor();
services.AddTransient<IUserContextServices, UserContextService>();

0
投票

我怀疑你真的需要构造函数,因为那一刻它将为空。

HttpContext
连接到底座类
Initialize
功能上的控制器。

您可以做的是覆盖,之前调用父级的

Initialize
函数,并按照您的预期指令进行操作,如下所示:

    protected override void Initialize(RequestContext requestContext)
    {
        base.Initialize(requestContext);

        // ... Do what ever you want with the already set HttpContext field
    }

我在旧的 .Net Framework 4 项目上对此进行了测试,我不确定我的方法是否在较新的 .Net Core 版本上也可行。

© www.soinside.com 2019 - 2024. All rights reserved.