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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扩展控制器构造函数没有User实例相关的知识,希望对你有一定的参考价值。

我有一个从Controller扩展的基本控制器,该类工作正常,但我认为我使用了很多次代码从数据库中获取当前用户。所以我想我应该创建一个构造函数并移动我在每个函数中使用的代码。基本上,我想要做的是为控制器中的任何方法准备好参数。

所以,这就是我现在所拥有的(并且工作正常):

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(Identity)

答案

听起来好像找不到用户,可能是因为调用控制器的构造函数时,线程的主体上没有填充用户标识。

我的建议是避免在构造函数中提取用户数据,而是在需要时抓取它。为避免重复代码,您可以编写受保护或私有方法(而不是操作方法)来获取它:

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);
        }
    }
}
另一答案

正如我在问题评论中提到的,继承在这里是一个糟糕的选择。相反,您尝试做的是向视图提供非特定数据。更好的选择是使用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>
}

以上是关于扩展控制器构造函数没有User实例的主要内容,如果未能解决你的问题,请参考以下文章

给定一个类型对象的实例,如何调用该类的构造函数(在其他语言中等效于GetConstructor)

片段事务中的实例化错误

为啥我收到此错误“没有构造函数实例”,CUDA 优化器中的 viennacl 库,C++ 控制台应用程序

在 Visual Studio 中创建构造函数的代码片段或快捷方式

简单代码需要帮助 - 没有构造函数实例匹配参数列表

ASP.NET Core 访问控制器构造函数中的 User.Identity