当函数未从 UI 调用时,用户为 null

本文关键字:用户 null 调用 函数 UI | 更新日期: 2023-09-27 18:33:20

在我的数据库表中,我有一列在保存到数据库之前对值进行操作。操作的逻辑是在开发的后期阶段添加的,在将大量值插入到表中之后。现在,我想编辑表的内容以操作现有内容的值。

我的方法

为表中的所有项调用编辑函数,因为操作逻辑也添加到 EDIT 操作方法中。

当我在循环访问数据库中的内容时调用编辑函数时,我得到一个空引用异常,当我从 UI 使用编辑函数时,该异常不存在。

编辑操作方法

    public ActionResult Edit([Bind(Include = "SetValueID,Value,Status,TcSetID,OptionValueID,CreatedOn,CreatedBy,ModifiedOn,ModifiedBy")] SetValue setValue)
    {
       //Many lines removed for simplicity. all the variables used in the code are assigned.
            if (ModelState.IsValid)
            {
                // Valuestring from another function
                setValue.Value = valuestring;
                var original = db.SetValue.Find(setValue.SetValueID);
                bool modified = original.Value != setValue.Value;
                if (modified)
                {
                    var rev = new RevisionHistory();
                    rev.CreatedOn = original.ModifiedOn;
                    rev.ModifiedBy = User.Identity.Name; //If modified exception on this line
                    db.Entry(original).CurrentValues.SetValues(setValue);
                    db.RevisionHistory.Add(rev);
                }
                original.ModifiedOn = DateTime.Now;
                original.ModifiedBy = User.Identity.Name; //if not modified exception on this line
                db.Entry(original).State = EntityState.Modified; 
                db.SaveChanges();
            }
    }

对此函数的调用是从 HomeController 进行的。我在 EDIT 方法中注释了所有返回语句,同时从 HomeController 调用它。

例外

对象引用未设置为对象的实例。

问题

为什么从UI调用时编辑工作,没有任何异常,而不是从HomeController调用?

为什么即使我从不同的控制器调用函数,用户也为 null?使用窗口身份验证。如果用户已经过身份验证,如何获取用户名?

编辑 - 添加了如何调用编辑函数

    //Home controller (But I have also tried calling the function from a different controller where the call to the method is from the UI
    public ActionResult Index()
    {
        test();
        return View();
    }
    public void test()
    {
        foreach(var item in db.SetValue.ToList())
        {
            var setvalcon = new SetValuesController();
            setvalcon.Edit(item);
        }     
    }

更新 - 问题的一般概述

可以概括该问题,以便找到在使用 Windows 身份验证时如何定义 User 属性的答案。

控制器是否仅在从 UI 调用 Windows 用户属性时才可以访问该属性?

是否无法访问未通过 UI 调用的函数中的用户属性?

据我所知,关于这个问题的最好的事情是,用户是在调用test方法的控制器中定义的,但不是在另一个控制器的Edit中定义的。

当函数未从 UI 调用时,用户为 null

当您说只能从 UI 访问 User 属性时,您是部分正确的。正确答案是——

通过 UI 访问 Edit 方法时,它实际上是通过 ASP.Net 控制器初始值设定项管道,该环境负责当前浏览器会话并分配 User 变量。 HttpContext目前可用。

但是当你像这样创建控制器变量时 -

var setvalcon = new SetValuesController();
setvalcon.Edit(item);

您正在绕过所有这些初始化代码。没有HttpContext,这只是另一个普通对象,因此它没有填充User属性。

问题回答:

  1. 控制器是否仅在从 UI 调用 Windows 用户属性时才可以访问该属性?

=> 是的,绝对正确,因为您正在经历 ASP.Net 管道。但它不仅适用于Windows用户,而且是HttpContext中的所有内容。

  1. 是否无法访问未通过 UI 调用的函数中的用户属性?

=> 仅当,您手动分配它,否则为否。

更多见解:

基本上,您要实现的是一个非常糟糕的设计。无处可去,记住无处可去,你应该从控制器内部调用控制器,除非它是基方法调用的子类。从另一个控制器内部调用另一个控制器的唯一方法是使用"重定向"方法重定向执行。没有人会阻止你这样调用控制器,但这显示了糟糕的设计原则。

解决你情况的最好办法是这样的——

public class ModelService {
    public void Edit(IPrincipal user, SetValue setValue){
        setValue.Value = valuestring;
            var original = db.SetValue.Find(setValue.SetValueID);
            bool modified = original.Value != setValue.Value;
            if (modified)
            {
                var rev = new RevisionHistory();
                rev.CreatedOn = original.ModifiedOn;
                rev.ModifiedBy = User.Identity.Name; //If modified exception on this line
                db.Entry(original).CurrentValues.SetValues(setValue);
                db.RevisionHistory.Add(rev);
            }
            original.ModifiedOn = DateTime.Now;
            original.ModifiedBy = User.Identity.Name; //if not modified exception on this line
            db.Entry(original).State = EntityState.Modified; 
            db.SaveChanges();
    }
}

然后在两个控制器构造函数中 -

public class ControllerOne : Controller {
    private readonly ModelService _modelService
    //constructor
    public ControllerOne(){
         _modelService= new ModelService ();
    }
    public ActionResult Edit([Bind(Include = "SetValueID,Value,Status,TcSetID,OptionValueID,CreatedOn,CreatedBy,ModifiedOn,ModifiedBy")] SetValue setValue)
    {
        //Many lines removed for simplicity. all the variables used in the code are assigned.
        if (ModelState.IsValid)
        {
            _modelService.Edit(User, Setvalue);
        }
    }
//controller 2
public class HomeController: Controller {
    private readonly ModelService _modelService
    //constructor
    public ControllerOne(){
         _modelService= new ModelService ();
    }
    public ActionResult Index()
    {        
        foreach(var item in db.SetValue.ToList())
        {
            _modelService.Edit(User, item);
        }     
    }
}

您可以从 IoC 容器获得帮助进行依赖注入,这是更好的方法。

从另一个控制器中调用控制器可能会丢失一些数据(作为用户(。我不会花太多精力去理解为什么(除非好奇(,因为这样做可能会被认为是糟糕的设计。(我敢打赌其他一些信息也会丢失,也许是饼干等(。您可以做的更好的事情是将控制器中的逻辑分离到某个服务层中,并使用IPrincipal用户作为参数调用这些方法。如果您被迫按照您描述的方式执行此操作,则将用户作为参数发送到另一个控制器。

public ActionResult Index()
{
    test(User);
    return View();
}
public void test(IPrincipal user)
{
    foreach(var item in db.SetValue.ToList())
    {
        var setvalcon = new SetValuesController();
        setvalcon.Edit(item, user);
    }     
}

而控制器

public ActionResult Edit([Bind(Include = "SetValueID,Value,Status,TcSetID,OptionValueID,CreatedOn,CreatedBy,ModifiedOn,ModifiedBy")] SetValue setValue, IPrincipal user = null)
{
   var currentUser = User == null? user : User;//or somthing like that
}

没有检查此代码。 但它应该给你一些工作。