深入了解懒惰加载和处理MVC .net中的错误 [英] Deep understanding of lazy loading and disposing error in MVC .net

查看:102
本文介绍了深入了解懒惰加载和处理MVC .net中的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为以下问题写一个完整的详细答案:
,如何将视图呈现为字符串,并将其作为action方法的返回类型返回。所以我可以使用延迟加载和渲染视图,而仍然在使用声明。



所以我做的是以下更改我的动作方法[解释被包含在评论中]

  // GET:/ dept / 
public string Index()
{

IView myView;
string result;
使用(var ctx = new ApplicationDbContext())
{
//我的模型带来了使用dbContext
IEnumerable< department> d = ctx.departments;

//现在因为我想渲染View这里[强制]而不是等待
//为正常的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;
//直到这一点,View没有呈现
StringWriter tw = new StringWriter(); //用于将视图转换为字符串
ViewContext vc = new ViewContext(ControllerContext,myView, ControllerContext.Controller.ViewData,ControllerContext.Controller.TempData,tw);
//它是以下方法.Render(viewContext,textWriter)将在IEnumerable< department>上开始迭代。对象
myView.Render(vc,tw);

result = tw.ToString(); //渲染的视图现在以字符串形式写入结果
tw.Dispose();
}

返回结果;
}
}

我很高兴看到我的页面呈现成功没有那个着名的处置错误;查看结果:








所以总结一下:



我的问题的答案是:



当您从您的操作方法返回一个ViewResult或ActionResult;视图仍未呈现。一旦它到达管道中,ViewEngine和ViewEngine触发方法.Render(),那么这个时候,懒惰的加载对象将需要dbContext,并将导致着名的Dispose错误的dbContext。
我还展示了如何在Action方法本身内呈现View。甚至在dbContext的using语句中;我可以逃避处理错误。



感谢大家:)


i was trying to write a full detailed answer to the following question: Why does "Dispose" work, and not "using(var db = new DataContext())"?

so I set up my project that include:

Departments and employees using entity framework

so my action method was this:

public ActionResult Index()
    {

        IEnumerable<department> d;
        using (var ctx = new ApplicationDbContext())
        {

            d = ctx.departments;

        }


        return View(d);
}

it is natural to expect that this will result in the common error :

The operation cannot be completed because the DbContext has been disposed

and when i wanted to resolve it I did the following [to force eager loading rather than easy loading] :

 public ActionResult Index()
    {

        IEnumerable<department> d;
        using (var ctx = new ApplicationDbContext())
        {

            d = ctx.departments.toList();

        }


        return View(d);
}

so I was trying to understand things under the hood and looked at the return type of the View() method. and I reached to the following 'Correct' assumptions:

1- the model [d] is called in lazy loading fashion inside the using statement.

2- so when the model [d] is sent to the view for generating the page the DbContext is already disposed by the last curly bracket of the using statement.

3- we solve this situation by sending the model [d] to the view with eager loading fashion.

then I continued my assumptions that proved to be 'wrong' as following:

4- since the View() method is returning ViewResult object which is an ActionResult also..then I can generate this object inside the using statement and then return it to the user.

so I did the following:

public ActionResult Index()
    {

        ActionResult myView;

        using (var ctx = new ApplicationDbContext())
        {

            IEnumerable<department> d = ctx.departments;

            myView =  View(d);

        }


        return myView;
    }

so I told myself now when I run it , the ViewResult object [ myView] will be already created and will be returned to the user and No Error will be encountered.

However I was surprised that the same error occured :

The operation cannot be completed because the DbContext has been disposed

I was astonished how this lazy loading is really lazy and load only at the last moment.

So I continued my 'wrong' assumptions as follow:

5- may be I need to force the View() method to excute the result inside the using statement. so I used the method ExecuteResult(ControllerContext).

and now I thought I can run the action method without any error but again the same error occured:

The operation cannot be completed because the DbContext has been disposed.

So my question now is:

where in the MVC framework does the excution of lazy loading query occur !!

or let me rephrase my question as follow:

Why did View(d) method iterate over the [d] object when it is out of the using statment, and not when the view(d) method is inside the using Statement.

I just need to understand why my assumptions were wrong .. Thanx in advanced

解决方案

Ok. I found a very convincing answer as follow:

I started to read about the MVC5 life-cycle and found many articles on the net. one of them is the following link: http://www.dotnet-tricks.com/Tutorial/mvc/TbR0041112-Asp.net-MVC-Request-Life-Cycle.html so I copied the picture and added my comment on it as the following [courtesy: www.dotnet-tricks.com]

then I read in another article [ here: http://www.codemag.com/Article/1312081] , how to render the view to string and returned that as the return type of the action method. so that I may be able to use the lazy loading and render the view while still inside the using statement.

so all I did was the following change to my action method [ explanation is included as comments]

 // 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;
    }
}

and I was happy to see that my page rendered successfully without that famous disposing error; see the result:


So to sum it up:

the answer to my question is :

when you return a ViewResult or ActionResult from your action method; the view is still not rendered. and once it reach in the pipeline to the ViewEngine and the ViewEngine trigger the method .Render(), it is at that time the lazy loading object will need the dbContext and will result in the famous Disposing error of the dbContext. I also showed how can you render the View inside the action method itself. and even inside the using statement of the dbContext; and I could escape that disposing error.

thank you for everyone :)

这篇关于深入了解懒惰加载和处理MVC .net中的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆