下面的示例代码抛出带有消息Object reference not set to an instance of an object.
的NullReferenceException
。错误是指User
属性为null
。
基本控制器
public class BaseController : Controller
{
public string UserName
{
get
{
return User.Identity.Name;
}
}
}
主控制器
[Authorize]
public class HomeController : BaseController
{
private string username { get; set; }
public HomeController()
{
username = UserName;
}
// GET: Home
public ActionResult Index()
{
ViewBag.UserName = username;
return View();
}
}
另一方面,如果直接在操作内部访问UserName
属性,则它可以正常工作。因此,如果将代码更改为:,则该代码有效
主控制器
[Authorize]
public class HomeController : BaseController
{
// GET: Home
public ActionResult Index()
{
ViewBag.UserName = this.UserName;
return View();
}
}
有什么想法吗?
更新:
因此,真正的问题是HttpContext在控制器的构建过程中不可用。我真的很奇怪为什么?有什么解释吗?另外,如果我需要使用构造函数DI来实例化依赖类,而依赖类又需要知道当前登录的用户,例如:
[Authorize]
public class HomeController : BaseController
{
private IMyService service;
public HomeController(IMyService service)
{
this.service = service;
this.service.UserName = UserName;
}
// GET: Home
public ActionResult Index()
{
// use service here ...
return View();
}
}
您无权访问构造函数中的HttpContext。如果你想在一个地方添加这样的检索逻辑,你可以用其中一种方法。
直接呼叫基本控制器
从基本控制器访问UserName
属性,无需将其重置为派生控制器上的属性或字段。
[Authorize]
public class HomeController : BaseController
{
// GET: Home
public ActionResult Index()
{
ViewBag.UserName = UserName;
return View();
}
}
挂钩到OnActionExecuting而不是ctor
设置Controller.OnActionExecuting中的值,而不是构造函数,因为此时您可以访问HttpContext。将override
添加到方法中以执行此操作。
扩展方法
请改为添加方法扩展。我更喜欢这种方法,因为我不喜欢控制器继承,只是从标准Mvc控制器继承。
public static class ControllerExtension {
public static string UserName(this Controller controller) {
return controller.User.Identity.Name;
}
}
你的代码变成
[Authorize]
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
ViewBag.UserName = this.UserName();
return View();
}
}
编辑
。。。其中构造函数DI用于实例化参数,该参数又具有需要设置的UserName属性。。。
您可能希望将HttpContextBase
实例注入到您的服务中,并让它以这种方式检索经过身份验证的用户名。您不希望Controller
实例需要向服务提供用户名,因为这会创建紧密耦合的代码并破坏SoC(关注点分离)。
class MyService : IMyService
{
public string UserName {get;}
// inject HttpContextBase
public MyService(HttpContextBase context){
this.UserName = context.User.Identity.Name;
}
}
这是因为构造函数中没有HttpContext
。只有在控制器实例化之后,才会分配User属性。
尝试在那里使用System.Web.HttpContext.Current.User
。