问题
I am getting the following error: Value cannot be null. Parameter name: principal
How can I access Identity (userId) inside the controller's constructor? I can only get it working by wrapping the failed call in a function (both highlighted below).
Is there anything I need to inject?
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
}
}
回答1:
As @Henk mentioned, the controller constructor will be executed before the ActionContext has been set, so you won't have access to properties like Context
, Request
or User
. You need to retrieve the userId within the context of a request.
You could use the old-fashioned approach of the action filters which are still part of the MVC6 pipeline (Which also supports async action filters via IAsyncActionFilter
).
Since you want to set a property in your controller, the most simple way you could implement this is by overriding the OnActionExecuting
method in your controller class. This works because you are inheriting from Controller, which already implements IActionFilter
.
public override void OnActionExecuting(ActionExecutingContext context)
{
//Get user id
userId = User.GetUserId();
}
Edit
If you check the DefaultControllerFactory you will see that:
- first the controller is created
then the ActionContext is set (Via the DefaultControllerPropertyActivator which is one of the property activators):
var controller = _controllerActivator.Create(actionContext, controllerType); foreach (var propertyActivator in _propertyActivators) { propertyActivator.Activate(actionContext, controller); }
回答2:
When the controller is instantiated there is no guarantee that the request information is avaiable in the HttpContext yet. There might not be a request at all. Is there reason why you need that information in the constructor?
Edit
I understand your issue. What I usually do in a scenario like this, is create a property with a backing field which only queries once per controller:
private int? _userId;
public int UserId
{
get
{
if (!_userId.HasValue)
{
// query from db.
_userId = 42;
}
return _userId.Value;
}
}
来源:https://stackoverflow.com/questions/33169060/user-getuserid-fails-inside-controllers-constructor