我收到以下错误:值不能为null。参数名称:principal
如何在控制器的构造函数中访问Identity(userId)?我只能通过将失败的调用包装在一个函数中来实现它(下面突出显示)。
我需要注射什么吗?
public class BaseController : Controller {
protected readonly MylDbContext dbContext;
protected readonly string userId;
public BaseController(MylDbContext dbContext) {
this.dbContext = dbContext;
userId = User.GetUserId(); // fails here
}
public string GetUserId() {
return User.GetUserId(); // works here
}
}
答案 0 :(得分:6)
正如@Henk所提到的,控制器构造函数将在ActionContext设置之前执行,因此您将无法访问Context
,Request
或User
等属性。您需要在请求的上下文中检索userId。
您可以使用action filters的老式方法,它仍然是MVC6管道的一部分(它还通过IAsyncActionFilter
支持异步操作过滤器。)
由于您要在控制器中设置属性,因此可以通过覆盖控制器类中的OnActionExecuting
方法来实现此操作。这是有效的,因为您继承了Controller
,它已经实现了IActionFilter
。
public override void OnActionExecuting(ActionExecutingContext context)
{
//Get user id
userId = User.GetUserId();
}
修改强>
如果您查看DefaultControllerFactory
,您会看到:
然后设置ActionContext(通过DefaultControllerPropertyActivator
,它是属性激活器之一):
var controller = _controllerActivator.Create(actionContext, controllerType);
foreach (var propertyActivator in _propertyActivators)
{
propertyActivator.Activate(actionContext, controller);
}
答案 1 :(得分:1)
当实例化控制器时,不能保证请求信息在HttpContext中可用。可能根本没有请求。你有理由在构造函数中需要这些信息吗?
修改强>
我理解你的问题。我通常在这样的场景中做的是创建一个带有后备字段的属性,每个控制器只查询一次:
private int? _userId;
public int UserId
{
get
{
if (!_userId.HasValue)
{
// query from db.
_userId = 42;
}
return _userId.Value;
}
}