以下示例代码抛出NullReferenceException
消息Object reference not set to an instance of an object.
。该错误指的是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();
}
}
答案 0 :(得分:4)
您无权访问构造函数中的HttpContext。如果您想要一个地方添加这样的检索逻辑,您可以通过以下方式之一来完成。
从基本控制器访问UserName
属性,无需将其重置为派生控制器上的属性或字段。
[Authorize]
public class HomeController : BaseController
{
// GET: Home
public ActionResult Index()
{
ViewBag.UserName = UserName;
return View();
}
}
在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;
}
}
答案 1 :(得分:0)
这是因为你在构造函数中没有HttpContext
。在实例化Controller之后才会分配User属性。
尝试在那里使用System.Web.HttpContext.Current.User
。