HttpContext null в конструкторе

У меня есть служба UserContext, в которую я добавлю некоторые основные функции ("IsAuthenticated, GetUser и т. д.).

Для этого мне нужно передать HTTPContext из моего контроллера WebAPI в мою службу библиотеки классов.

На самом деле, HttpContext всегда null в контроллере веб-API.

У кого-нибудь есть решение моей проблемы? Есть ли лучший способ добиться этого.

Контроллер пользователей веб-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;
        }
    }
}

person Jean-Francois    schedule 21.06.2017    source источник
comment
В потоке вызова контроллера HttpContext не готов/назначен во время создания контроллера. Переосмыслите дизайн, чтобы контекст внедрялся позже в жизненном цикле зависимого класса.   -  person Nkosi    schedule 21.06.2017
comment
Какой метод вызывается после конструктора?   -  person Jean-Francois    schedule 21.06.2017


Ответы (1)


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>();
person Nkosi    schedule 21.06.2017