User.GetUserId()在控制器的构造函数中失败

时间:2015-10-16 11:11:13

标签: asp.net asp.net-core asp.net-core-mvc

我收到以下错误:值不能为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
    }
}

2 个答案:

答案 0 :(得分:6)

正如@Henk所提到的,控制器构造函数将在ActionContext设置之前执行,因此您将无法访问ContextRequestUser等属性。您需要在请求的上下文中检索userId。

您可以使用action filters的老式方法,它仍然是MVC6管道的一部分(它还通过IAsyncActionFilter支持异步操作过滤器。)

由于您要在控制器中设置属性,因此可以通过覆盖控制器类中的OnActionExecuting方法来实现此操作。这是有效的,因为您继承了Controller,它已经实现了IActionFilter

public override void OnActionExecuting(ActionExecutingContext context)
{
    //Get user id   
    userId = User.GetUserId();
}

修改

如果您查看DefaultControllerFactory,您会看到:

  1. 首先创建控制器
  2. 然后设置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;
    }
}