C# 深入理解MVC.net中的延迟加载和处理错误
我试图对以下问题写一个完整详细的答案: 因此,我设立了我的项目,包括: 使用实体框架的部门和员工 所以我的行动方法是:C# 深入理解MVC.net中的延迟加载和处理错误,c#,asp.net-mvc,entity-framework,lazy-loading,C#,Asp.net Mvc,Entity Framework,Lazy Loading,我试图对以下问题写一个完整详细的答案: 因此,我设立了我的项目,包括: 使用实体框架的部门和员工 所以我的行动方法是: public ActionResult Index() { IEnumerable<department> d; using (var ctx = new ApplicationDbContext()) { d = ctx.departments; }
public ActionResult Index()
{
IEnumerable<department> d;
using (var ctx = new ApplicationDbContext())
{
d = ctx.departments;
}
return View(d);
}
当我想解决这个问题时,我做了以下几件事[强制迫不及待地加载,而不是简单地加载]:
public ActionResult Index()
{
IEnumerable<department> d;
using (var ctx = new ApplicationDbContext())
{
d = ctx.departments.toList();
}
return View(d);
}
我很惊讶这种惰性加载是多么的懒惰,而且只在最后一刻加载
因此,我继续我的错误假设如下:
5-可能我需要强制View()方法在using语句中执行结果。所以我使用了方法executesult(ControllerContext)
现在我想我可以毫无错误地运行action方法了
但同样的错误再次出现:
The operation cannot be completed because the DbContext has been disposed.
所以我现在的问题是:
在MVC框架中执行延迟加载查询的位置强>
或者让我将我的问题重新表述如下:
为什么View(d)
方法在[d]对象不在using语句中时迭代它,而不是在View(d)方法在using语句中时迭代它。
我只需要理解为什么我的假设是错误的。。
高级IEnumerable
中的Thanx是一个允许延迟执行的接口。事实上,延迟执行是LINQ高效的根本原因。现在,您的假设都是正确的,但是您缺少一个关键概念:在.NET中以延迟执行的形式延迟加载实现
了解强制枚举如何立即计算延迟代码。第一个示例工作的原因是调用了ToList()
,强制枚举并执行代码。在第二种情况下,对视图对象的分配保持延迟,因为没有通过将结果分配给view
但是,您可以在using块内执行此操作,以强制代码在执行dispose之前执行:
IEnumerable<department> d = ctx.departments;
// ToList() here forces the evaluation of the deferred code
myView = View(d.ToList());
IEnumerable d=ctx.departments;
//这里的ToList()强制计算延迟代码
myView=View(d.ToList());
回答您关于MVC管道的问题:MVC管道不会计算您放置在
ViewResult
中的对象,只是为了使视图本身能够使用它而对其进行适当的强制转换。因此,它从不执行枚举并强制执行代码。在您的视图中,这是您的呼叫。。。在这种情况下,类似于foreach
ing您的Model
。因此,当您的视图执行时,您的using
语句早已被释放,因此延迟调用将失败。许多LINQ方法将对序列进行流式处理,有些方法要求对整个序列进行缓冲和操作,但如果您对序列不做任何操作,它将不存在于内存中。确定。我发现一个非常令人信服的答案如下:
我开始阅读有关MVC5生命周期的文章,并在网上找到了许多文章。其中之一是以下链接:
因此,我复制了这张照片并添加了我的评论如下[礼貌:www.dotnet-tricks.com]
然后,我在另一篇文章[here:]中阅读了如何将视图呈现为string,并将其作为action方法的返回类型返回。这样,我就可以在using语句中使用延迟加载并呈现视图
因此,我所做的只是对我的行动方法做了以下更改[解释包括在评论中]
// GET: /dept/
public string Index()
{
IView myView;
string result;
using (var ctx = new ApplicationDbContext())
{
//my model brought using the dbContext
IEnumerable<department> d = ctx.departments;
// now because I want to render the View here [forcibly] and not waiting
//for the normal MVC pipeline to render my View I had to jump to the ViewEngine
//and ask it to render my View [while i am still inside this using statement]
// so referring to the excellent article on :http://www.codemag.com/Article/1312081
//I did the following:
ControllerContext.Controller.ViewData.Model = d;
ViewEngineResult viewEngResult = ViewEngines.Engines.FindView(ControllerContext, "~/Views/dept/Index.cshtml", null);
myView = viewEngResult.View;
//till this point the View is not rendered yet
StringWriter tw = new StringWriter();// used to render the View into string
ViewContext vc = new ViewContext(ControllerContext, myView, ControllerContext.Controller.ViewData, ControllerContext.Controller.TempData, tw);
//it is the following method .Render(viewContext, textWriter) that will start iterating on the IEnumerable<department> object
myView.Render(vc, tw);
result = tw.ToString();// the rendered View is now written as string to the result
tw.Dispose();
}
return result;
}
}
//获取:/dept/
公共字符串索引()
{
我的观点;
字符串结果;
使用(var ctx=new ApplicationDbContext())
{
//我的模型使用dbContext
IEnumerable d=ctx.departments;
//现在,因为我想在这里(强制)渲染视图,而不是等待
//为了让普通MVC管道渲染我的视图,我必须跳转到ViewEngine
//并要求它呈现我的观点[当我还在使用此语句时]
//因此,请参考关于以下内容的优秀文章:http://www.codemag.com/Article/1312081
//我做了以下工作:
ControllerContext.Controller.ViewData.Model=d;
ViewEngineResult viewEngResult=ViewEngines.Engines.FindView(ControllerContext,“~/Views/dept/Index.cshtml”,null);
myView=viewEngResult.View;
//到目前为止,还没有渲染视图
StringWriter tw=new StringWriter();//用于将视图渲染为字符串
ViewContext vc=新的ViewContext(ControllerContext,myView,ControllerContext.Controller.ViewData,ControllerContext.Controller.TempData,tw);
//以下方法.Render(viewContext,textWriter)将开始迭代IEnumerable对象
myView.Render(vc,tw);
result=tw.ToString();//渲染视图现在作为字符串写入结果
tw.Dispose();
}
返回结果;
}
}
我很高兴看到我的页面成功呈现,没有出现著名的处理错误;看到结果:
总之: 我的问题的答案是: 当您从action方法返回ViewResult或ActionResult时,该视图仍不会被渲染。一旦它进入到ViewEngine的管道中,ViewEngine就会触发该方法。Render(),此时延迟加载对象将需要dbContext,并将导致著名的dbContext处理错误。 我还展示了如何在action方法本身内部,甚至在dbContext的using语句内部呈现视图;我可以避免这个错误
谢谢大家:)这并没有回答MVC框架何时将
IEnumerable
计算为其值的问题;相反,它只会重复
The operation cannot be completed because the DbContext has been disposed.
IEnumerable<department> d = ctx.departments;
// ToList() here forces the evaluation of the deferred code
myView = View(d.ToList());
// GET: /dept/
public string Index()
{
IView myView;
string result;
using (var ctx = new ApplicationDbContext())
{
//my model brought using the dbContext
IEnumerable<department> d = ctx.departments;
// now because I want to render the View here [forcibly] and not waiting
//for the normal MVC pipeline to render my View I had to jump to the ViewEngine
//and ask it to render my View [while i am still inside this using statement]
// so referring to the excellent article on :http://www.codemag.com/Article/1312081
//I did the following:
ControllerContext.Controller.ViewData.Model = d;
ViewEngineResult viewEngResult = ViewEngines.Engines.FindView(ControllerContext, "~/Views/dept/Index.cshtml", null);
myView = viewEngResult.View;
//till this point the View is not rendered yet
StringWriter tw = new StringWriter();// used to render the View into string
ViewContext vc = new ViewContext(ControllerContext, myView, ControllerContext.Controller.ViewData, ControllerContext.Controller.TempData, tw);
//it is the following method .Render(viewContext, textWriter) that will start iterating on the IEnumerable<department> object
myView.Render(vc, tw);
result = tw.ToString();// the rendered View is now written as string to the result
tw.Dispose();
}
return result;
}
}