我有一个从Controller扩展的基本控制器,该类运行良好,但是我发现我经常使用代码从数据库中获取当前User。所以我想应该构造一个构造器,并移动在那里的每个函数中使用的代码。 基本上,我想做的是为控制器中的任何方法准备好参数。
所以,这就是我现在所拥有的(并且工作正常):
public class UsersController : Controller
{
private DBContext db = new DBContext();
public ActionResult Info()
{
User user = db.Users.Where(m => m.username.Equals(User.Identity.Name)).FirstOrDefault();
return View(user);
}
public ActionResult Edit(int? id){
User user = db.Users.Where(m => m.username.Equals(User.Identity.Name)).FirstOrDefault();
if(user.id == id){
return View(user);
}
}
}
但是我的想法是创建这样的东西:
public class UsersController : Controller
{
private DBContext db = new DBContext();
private User _user;
public UsersController()
{
_user = db.Users.Where(m => m.username.Equals(User.Identity.Name)).FirstOrDefault();
}
public ActionResult Info()
{
return View(_user);
}
public ActionResult Edit(int? id){
if(_user.id == id){
return View(_user);
}
}
}
进行这些更改时,出现以下错误:
“ /”应用程序中的服务器错误。 对象引用未设置为对象的实例。
描述:在执行当前Web请求期间发生未处理的异常。请查看堆栈跟踪,以获取有关错误及其在代码中起源的更多信息。
异常详细信息:System.NullReferenceException:对象引用未设置为对象的实例。
我尝试调试,发现问题是调用构造函数时我的 User
是 null
,所以我猜想,其他一些语言可以在添加自己的自定义之前或之后调用父构造函数,例如:
public function __Construct($x){
$this->x = $x
parent::__construct();
}
或
public function __Construct($x){
parent::__construct();
$this->x = $x
}
我尝试使用 base
在程序中执行相同的操作,但是似乎没有任何效果,它总是导致我遇到其他性质的错误。
我什至不确定这是正确的方法,因为我只需要在构造函数中创建我的 User
(身份)
答案 0 :(得分:1)
找不到类似用户的声音,可能是因为在调用控制器的构造函数时,没有在线程主体上填充用户标识。
我的建议是避免在构造函数中提取用户数据,而是在需要时获取它。为了避免重复代码,您可以编写一个受保护的或私有的方法(不是操作方法)来获取它:
public class UsersController : Controller
{
private DBContext db = new DBContext();
private User GetCurrentUser()
{
return db.Users.Where(m => m.username.Equals(User.Identity.Name)).FirstOrDefault();
}
public ActionResult Info()
{
var user = GetCurrentUser();
return View(user);
}
public ActionResult Edit(int? id){
var user = GetCurrentUser();
if(user.id == id){
return View(user);
}
}
}
答案 1 :(得分:0)
正如我在问题注释中提到的那样,在这里继承是一个糟糕的选择。相反,您要尝试的是向视图提供非特定数据。更好的选择是使用ActionFilter。
我们需要一个类来存储用户信息以供视图使用:
public class UserInfo
{
public bool HasUser { get; set; }
public User User { get; set; }
}
我们需要一个地方来存储非特定于视图的数据。我更喜欢使用ViewData(因为此路由提供了强类型数据和调试此存储位置的简便方法):
public static class ViewDataExtensions
{
private const string UserInfoKey ="_UserInfo";
public static void GetUserInfo(this ViewData viewData)
{
return viewData.ContainsKey(UserInfoKey)
? viewData[UserInfoKey] as UserInfo
: null;
}
public static UserInfo SetUserInfo(this ViewData viewData, UserInfo userInfo)
{
viewData[UserInfoKey];
}
}
接下来,我们需要一种在需要时填充该信息的方法
public class AddUserToViewDataFilterAttribute : ActionFilterAttribute
{
private DBContext db = new DBContext();
public void OnActionExecuting(ActionExecutingContext context)
{
var user = context.Controller.User;
var userInfo = new UserInfo
{
HasUser = !string.IsNullOrEmpty(User.Identity?.Name),
User = !string.IsNullOrEmpty(User.Identity?.Name)
? db.Users
.Where(m => m.username.Equals(User.Identity.Name)).FirstOrDefault()
: null;
};
context.ControllerContext.ViewData.SetUserInfo(userInfo);
}
}
在需要时填充它:
public class MyController
{
public ActionResult DoesNotNeedUserInfo()
{
}
[AddUserToViewDataFilter]
public ActionResult NeedsUserInfo()
{
}
}
在视图中:
@model <whatever>
@if (ViewData.GetUserInfo().HasUser) {
<div>@ViewData.GetUserInfo().User.Name</div>
}