扩展控制器构造函数没有User

时间:2018-12-21 20:51:40

标签: c# asp.net-mvc inheritance constructor extends

我有一个从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 (身份)

2 个答案:

答案 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>
}