未从 UI 调用函数时用户为空

User is null when Function not called from UI

在我的数据库中 table 我有一个列,其中的值在保存到数据库之前进行了操作。在向 table 插入大量值之后,在开发的后期添加了操作逻辑。现在我想编辑 table 的内容来操作现有内容的值。

我的做法

为table中的所有项目调用编辑功能,因为在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 进行的。我在从 HomeController 调用 EDIT 方法时注释了所有 return 语句。

异常

Object reference not set to an instance of an object.

问题

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

为什么即使我从不同的控制器调用该函数,用户仍为空?使用 windows 身份验证。如果用户已通过身份验证,如何获取用户名?

编辑 - 添加了如何调用编辑功能

    //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 身份验证时如何定义用户 属性 的答案。

控制器是否只有在从UI调用时才能访问Windows用户属性?

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

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

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

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
}

没有检查此代码。但它应该会给你一些有用的东西。

当您说只能从 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 调用的函数中访问用户 属性?

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

更多见解:

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

解决你的情况的最好方法是这样 -

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 Container 进行依赖注入,这是更好的方法。