未从 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
属性。
问题的回答:
- 控制器是否只有在从 UI 调用时才能访问 Windows 用户 属性?
=> 是的,完全正确,因为您正在通过 ASP.Net 管道。但这不仅适用于 Windows 用户,它还适用于 HttpContext 中的所有内容。
- 是否无法在未通过 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 进行依赖注入,这是更好的方法。
在我的数据库中 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
属性。
问题的回答:
- 控制器是否只有在从 UI 调用时才能访问 Windows 用户 属性?
=> 是的,完全正确,因为您正在通过 ASP.Net 管道。但这不仅适用于 Windows 用户,它还适用于 HttpContext 中的所有内容。
- 是否无法在未通过 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 进行依赖注入,这是更好的方法。