在WebForm中,执行Response.End()会停止该页的执行,这导致其后的代码不会被执行。我经常利用这一特性,方便地从多层的调用中直接退出,而无需逐层返回至最初的调用方。 但是,在MVC4中,我尝试了所有能想到的方式去测试Response.End(),其后的代码总是会执行,这一行为与WebForm不一致。 请问: 1、在MVC4中,为什么Response.End()之后的代码会被执行? 2、在MVC中,如何让Response.End()之后的代码不被执行? 3、如果MVC中无法让Response.End()之后的代码不被执行,那么,有什么替代的方案来实现“其后的代码不被执行”的功能?
附: 阅读至此的园友,即使暂未找到上述3题的答案,也请花点时间,和更多的园友们分享你对以下3题的答案: 4、最近1年内你经手过的项目,百分之几采用MVC、百分之几采用WebForm、以及其它? 5、最近1年内你经手过的项目,百分之几采用ADO.NET、百分之几采用Entity Framework、以及其它? 6、如果在过去的项目中你已使用MVC,请问,你是否遇到上述“Response.End()在MVC与WebForm中行为不一致”的问题?
---------------问题未解决,换个方式请教大家---------------
学习、使用Asp.Net近6年了,这是第一次正式在网上提问。因为这是第一次遇到自己查资料解决不了的问题。 真心感谢imfunny、空葫芦、幻天芒、bree、s_p花时间脑力为我解惑。 但这个问题还是没有解决。 看到alone__的回复,我意识到可能我这问题问得不好,因此,就上述问题,我写了两段伪代码,请大家再帮我看看。谢谢alone__的指正。
以下伪代码功能说明: 客户端用ajax向服务器发出POST请求,服务器返回表示执行成功或失败的字符串信息。客户端收到服务器返回的字符串,alert(),完毕。 客户端代码简单,这里就省略了。 下面的服务器代码共2组,第1种是ashx方式的,第2种是mvc方式的。
----------ashx方式的伪代码,用Response.End()从任何深嵌套中立刻退出,无需逐层依次返回----------
public class HandlerTest : IHttpHandler { public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { Method0(); Method1(); Method2(); //Method1、Method2与Method0类似。实际业务中此处可能会有更多类似的代码需要执行。 context.Response.Write("All methods success."); } private void Method0() { //do something. if(执行失败) { HttpContext.Current.Response.Write("Method 0 failure."); //停止后续代码的执行、直接输出至客户端,无需逐层返回调用方: HttpContext.Current.Response.End(); } //do something. } }
---------------MVC方式的伪代码---------------
public class TestAjaxController : Controller { public ActionResult Test() { string msg = "All methods success."; if(Method0()) { if(Method1()) { if(Method2()) { //更多的Method需要执行。而且,如果前面的Method执行失败,必须停止执行后面的Method。 } else { msg = "Method 2 failure."; } } else { msg = "Method 1 failure."; } } else { msg = "Method 0 failure."; } return Content(msg); } private bool Method0() { //do something. } //Method1、Method2与Method0类似。 }
---------------代码演示完毕---------------
请大家用更优雅的MVC代码帮我实现上述业务需求,谢谢。
你只用了Response.End(),但是return了吗?
————————————————————————————
100% ASP.NET MVC,其他的都是组件或者Console,不涉及webform或者MVC
30%ADO.NET,70%是一种特别的支持Fluent API的ORM
————————————————————————-————
update at 7.1
ashx那里“//停止后续代码的执行、直接输出至客户端,无需逐层返回调用方:”应该是不准确的,你就算在method0里面使用了response.end(),但是method1和method2还是执行了的,可以用Debug.WriteLine()看一下调试窗口输出的。
MVC部分的伪代码,为什么不改用throw exception的方式实现呢,如果需求复杂,可以用自定义的异常。
public class HomeController : Controller { public ActionResult Index() { string msg = "All methods success."; try { Method0(); Method1(); Method2(); } catch (Exception e) { msg = e.Message; } return Content(msg); } private bool Method0() { Debug.WriteLine("Method 0 process."); bool flag = true; if (!flag) { throw new Exception("Method 0 failure"); } return flag; } private bool Method1() { Debug.WriteLine("Method 1 process."); bool flag = false; if (!flag) { throw new Exception("Method 1 failure"); } return flag; } private bool Method2() { Debug.WriteLine("Method 2 process."); bool flag = true; if (!flag) { throw new Exception("Method 2 failure"); } return flag; } }
空葫芦 你好!非常高兴你的关注。
一、关于Response.End()
最近6年一直在WebForm中使用Response.End(),从未遇到Response.End()之后的代码还能被执行的情况。
今天在VS2008与VS2012的WebForm中、尝试System.Diagnostics的Debug和Trace进行各种Write(),无论Debug还是Release,从未遇到Response.End()之后的代码还能被执行的情况。
所以我的结论是:Response.End()之后的代码是否会被执行,在WebForm与MVC中不一致:前者总是不执行、后者总是执行。
如果大家有不同的结论,请给出完整代码。
二、关于throw Exception
我提问时所使用的示例的本质是:在WebForm中我用Response.End()来控制程序的流程,但在MVC中无法如此便利地控制程序流程。
之所以没有考虑使用异常,是因为我总是不愿意用异常来控制程序的流程。
——————————————— 关键 ———————————————
请问除了使用异常,MVC中,是否还有更优雅的方式实现上述业务流程?
@OldStudent: 一试之下,还真的发现了点有意思的问题。我们说得似乎都不全对,LZ可以先看一下这几个链接。我稍后再补充回复
http://bbs.csdn.net/topics/330087387
http://www.shubho.net/2011/01/handling-threadabortexception-with.html
http://msdn.microsoft.com/zh-cn/library/system.web.httpresponse.end(v=vs.100).aspx
————————-————————————
update:7-1 18:17
MVC中调用的Response.End是这里的
http://msdn.microsoft.com/zh-cn/library/system.web.httpresponsebase.end(v=vs.100).aspx
应该和HttpContext.Current.Response.End()的实现有别
—————————————————————
update:7-1 18:28
在MVC中使用System.Web.HttpContext.Current.Response.End();显式调用和非MVC一样的这个方法,但是并没有引发异常。不知是何原因,
没有引发异常,也就不能去控制“不执行其后代码“这个流程控制~~~
google了一下,看到了不少资料,明天再看了先下班。
在此向LZ致歉,不管由于何种原因,而且个人觉得用return控制流程更为正道,但是之前的回答的确有错漏之处,并不完全。
你好 空葫芦,非常感谢! 如你所说,我也发现从.NET Frameworks 3.5开始多了HttpResponseBase这个类。 MSDN:在WebForm中,HttpResponse 类的方法和属性通过 HttpApplication、HttpContext、Page 和 UserControl 类的 Response 属性公开。 测试发现,不出所料,object.ReferenceEquals(Page.Response, HttpContext.Current.Response)的结果为true。 但是,在MVC中,出现了以下2个: System.Web.HttpResponse System.Web.HttpResponseBase 前者是从.NET Framework 1.1开始就有的,包括Page.Response、HttpContext.Response等。 后者是从.NET Framework 3.5新增的,从MVC的View中通过WebPageRenderingBase.Response可get。 这新旧2种Response的End(),在MVC中都不再停止后续代码的执行,与WebForm中不一致了。 我还发现: 将HttpContext.Current.Response.End()置于try块中, 在WebFrom中可catch到[System.Threading.ThreadAbortException] = {由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值。}; 但是在MVC中catch不到任何异常。 我理解为: 在WebFrom中,因为抛出的这个特殊的异常直接转到框架去处理了,所以后续代码不被执行。 而在MVC中,似乎没有抛出这种异常、没有将流程转到框架去处理,所以后续代码继续被执行。 不知道这是不是真正的原因?不知道微软为什么偷偷地要改变End()的行为? 我面向对象很弱,每次尝试读微软的源码,自觉水平太太差,非常受伤,也就只能自己琢磨到这一步了,于是就有了这次在博客园的提问,期待着大家的帮助了,
@OldStudent: 现在只能确认以下几点,为了避免混淆方法直接带上完整的命名空间了
1.webform下使用System.Web.HttpContext.Current.Response.End()首先引发了一个异常,在异常处理完(执行完catch中代码)后到执行Application_EndRequest()
2.如果不使用System.Web.HttpContext.Current.Response.End(),自己人为地去throw一个异常而不捕获,可以在代码层面达到同样的效果(但是输出页面会报错),不知System.Threading.ThreadAbortException有何特殊之处(目前只知道他是继承于SystemException,)
3.MVC可能是因为如果没有return View()就不能把Model传到View,继而不能构造视图,因此采取了和webform不同的处理机制。
不管出发点如何,依然不清楚最核心最根本的原因,简单一句话说就是:是什么导致了System.Web.HttpContext.Current.Response.End()在webform下引发了异常而在ASP.NET MVC没有。
@OldStudent:
目前也只能确认是设计上的差异,或许深究到底(内部机制是怎么区分处理的)意义已经不大。因为就算MVC里面Response.End()之后停止执行,你总要return一个ActionResult吧。
如果非要实现和webform中一样的,你可以使用Thread.CurrentThread.Abort()方法,这个方法会引发一个ThreadAbortException异常,就像webform中那样。
此时页面会直接输出而没有和视图关联起来(提示的异常也和throw new Exception()不同),如果你的这个路由本身就没有视图部分,只是通过Action方法执行打印一些数据,这倒也不是不不行。
只是个人始终觉得有点别扭,不过个人能力所限,找不到更好的办法了。
@OldStudent: 最终在台湾同胞保哥这里找到了答案,请LZ参见:
此文章下的评论以及
空葫芦你好,多谢你的帮助,让我弄明白了这个问题。 我在广州,请问你在哪个城市?不知道近不近,近的话请你喝茶/酒。
@OldStudent: 实在太客气啦。我现在也在广州,华景这边,喝茶/酒就不必啦,有什么技术会议可以相约参加下~~:)
1、End(),表示不往浏览器输出数据了。这个和 Response.Redirect(string url,bool endResponse),比较类似。
Response.End()不能终止整个代码的运行。
2、直接return即可。
3、Na
4、30%MVC,50%WebForms,其他WinForm
5、10%Ado.Net,30%LinqToSql,5%Entity Framework,30% iBatis,25%各种Orm。
6、暂时没,虽然是两种不同的开发模式,不过用了MVC之后,就不太喜欢WebForms了,现在的网页,对交互要求比较高,在WebForms中使用jquery等没在mvc中更简洁~
如果用goto的话,哈哈...
呵呵,我不抗拒使用goto,只是goto有范围限制,只能在方法体内跳转,无法跳转回方法外的调用方,上述业务逻辑中用不上。
@OldStudent: 我发现我想多了,你哪儿想终止,直接return Content(msg);不就ok了?
http://msdn.microsoft.com/en-us/library/ms525405(v=vs.90).aspx
Response.End
Stops processing the .asp file and returns the current result
MVC 是管线设计 是 IHttpHandler -->MvcRouteHandler 类比 webform ASHX
加retrun 吧
ef就算了 小项目还可以用用 是个花瓶
看的好累,
最近做项目遇到这个问题, 也感觉很困惑,搜到楼主这里来了。
的确, 在webform中 response.End() 不仅仅是终止输出,而同时函数也终止了;
基于此习惯,最近用MVC做手机APP的服务器端,大量用到 不同的条件下不同的 response.write(); response.End() ;
以为跟webform一样后面的函数就不会继续执行,结果测试不对, 检查之后发现在MVC中response.End() 之后的代码百分之百还会继续执行,
最终我又回头把所有的response.End()后面增加了 return;
good
收藏 之前没注意这个问题
ActionResult empty = new EmptyResult();return empty;重定向后,返回个这么个玩意儿。空