1

我有一個的UserContext服務,我就會把一些基本的功能(」 IsAuthenticatedGetUser等)的HttpContext空的構造

爲了做到這一點,我需要從我的WebAPI控制器通過HTTPContext我的類庫服務。

其實,HttpContext總是null在Web API控制器。

任何人有一個解決方案來解決我的問題? 有沒有更好的方式來acheive它。

的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); 
    } 
} 

的UserContext服務

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; 
     } 
    } 
} 
+0

在調用控制器的流程中,在創建控制器時HttpContext未準備好/分配。重新考慮設計,以便在相關類的生命週期中稍後使用注入的上下文 – Nkosi

+0

在構造函數之後調用哪個方法? –

回答

2

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.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 
services.AddTransient<IUserContextServices, UserContextService>();