在我的数据库表中,我有一个列,在保存到数据库之前操作这些值。在将大量值插入表格之后,在开发的后期阶段添加了操作的逻辑。现在我想编辑表的内容来操纵现有内容的值。
我的方法
要在表格中的所有项目中调用编辑功能,因为操作逻辑也会添加到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语句。
异常
对象引用未设置为对象的实例。
问题
为什么编辑在从UI调用时没有任何异常,但不是来自HomeController?
即使我从另一个控制器调用该函数,为什么用户为null?使用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身份验证时如何定义User属性的答案。
只有从UI调用它时,控制器才能访问Windows用户属性吗?
是否无法在未通过UI调用的函数中访问用户属性?
就我所知,问题最好的是,用户在Controller中被定义,test
方法被调用,但不在另一个控制器的Edit
中。
答案 0 :(得分:3)
当您说您只能访问仅从UI访问的User
属性时,您是部分正确的。正确答案是 -
当通过UI访问Edit
方法时,它实际上是通过ASP.Net控制器初始化程序管道,该环境负责当前的浏览器会话并分配User
变量。目前可以使用HttpContext
。
但是当你创建像这样的控制器变量时 -
var setvalcon = new SetValuesController();
setvalcon.Edit(item);
您正在绕过所有这些初始化代码。没有HttpContext
,这只是另一个普通对象,因此没有填充User
属性。
=>是的,绝对正确,因为您正在浏览ASP.Net管道。但它不仅适用于Windows用户,而是HttpContext中的所有内容。
=>只有在您手动分配否则否。
基本上,你想要实现的是一个非常糟糕的设计。没有地方,记得无处,你应该从控制器内部调用控制器,除非它是基础方法调用的子类。从另一个控制器内部调用另一个控制器的唯一方法是使用“重定向”方法重定向执行。没有人会阻止你这样调用控制器,但这显示了糟糕的设计原则..
解决问题的最佳方法就是这样 -
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获取依赖注入的帮助,这是更好的方法。
答案 1 :(得分:1)
从另一个Controller中调用Controller可能会使某些数据(作为用户)丢失。我不会做太多努力来理解为什么(除非好奇),因为这样做可能被认为是糟糕的设计。 (我打赌其他一些信息也会丢失,也许是饼干等)。您可以做的更好的事情是将逻辑与控制器分离到某个服务层,并使用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);
}
}
和oter控制器
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
}
没有检查此代码。但它应该给你一些工作。