玩转C科技.NET

从学会做人开始认识这个世界!http://volnet.github.io

导航

The ThreadAbortException from Response.End()

/// <devdoc>
///    <para> 
///       Terminates execution of the current page and begins execution of a new
///       request using the supplied URL path.
///       If preserveForm is false, the QueryString and Form collections are cleared.
///    </para> 
/// </devdoc>
public void Transfer(string path, bool preserveForm) { 
    Page page = _context.Handler as Page; 
    if ((page != null) && page.IsCallback) {
        throw new ApplicationException(SR.GetString(SR.Transfer_not_allowed_in_callback)); 
    }

    // execute child request
 
    Execute(path, null, preserveForm);
 
    // suppress the remainder of the current one 

    _context.Response.End(); 
}

都问页面跳转,然后大家都知道Server.Transfer与Request.Redirect的区别。

因为是页面跳转,所以理所应当地被用上了Response.End方法,而此举却引发了一些异常(http://support.microsoft.com/kb/312629)。

所以用Server.Execute就可以避免这个错误了。

详细如下:

对于 Response.End,调用 HttpContext.Current.ApplicationInstance.CompleteRequest 方法而不是 Response.End 以跳过 Application_EndRequest 事件的代码执行。
对于 Response.Redirect,请使用重载 Response.Redirect(String url, bool endResponse),该重载对 endResponse 参数传递 false 以取消对 Response.End 的内部调用。例如:
  Response.Redirect ("nextpage.aspx", false);

如果使用此替代方法,将执行 Response.Redirect 后面的代码。
对于 Server.Transfer,请改用 Server.Execute 方法。

顺便让我们看看Response.End都做了些什么

/*
 * Cancelles handler processing of the current request 
 * throws special [non-]exception uncatchable by the user code
 * to tell application to stop module execution. 
 */ 

/// <devdoc> 
///    <para>Sends all currently buffered output to the client then closes the
///       socket connection.</para>
/// </devdoc>
public void End() { 

    if (_context.IsInCancellablePeriod) { 
        InternalSecurityPermissions.ControlThread.Assert(); 
        Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
    } 
    else {
        // when cannot abort execution, flush and supress further output
        if (!_flushing) { // ignore Reponse.End while flushing (in OnPreSendHeaders)
            Flush(); 
            _ended = true;
 
            if (_context.ApplicationInstance != null) { 
                _context.ApplicationInstance.CompleteRequest();
            } 
        }
    }
}

关于InternalSecurityPermissions.ControlThread.Assert()请参考http://msdn.microsoft.com/zh-cn/library/system.security.codeaccesspermission.assert(VS.80).aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;

namespace WebAppThreadAbortException
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
             Do1Nothing();
            // Do1NothingWithoutException();
            // Do2ResponseEnd();
            // Do3Redirect();
            // Do4Transfer();
        }

        private void Do1Nothing()
        {
            Thread.CurrentThread.Abort();
        }

        private void Do1NothingWithoutException()
        {
            try
            {
                Thread.CurrentThread.Abort();
            }
            catch
            {
                Thread.ResetAbort();
            }
        }

        private void Do2ResponseEnd()
        {
            try
            {
                Response.End();
            }
            catch (ThreadAbortException ex)
            {
                Response.Write(FormatException(ex.ToString()));
            }
        }

        private void Do3Redirect()
        {
            try
            {
                Response.Redirect("NextPage.aspx");
            }
            catch (ThreadAbortException ex)
            {
                Response.Write(FormatException(ex.ToString()));
            }
        }

        private void Do4Transfer()
        {
            try
            {
                Server.Transfer("NextPage.aspx");
            }
            catch (ThreadAbortException ex)
            {
                Response.Write(FormatException(ex.ToString()));
            }
        }

        private string FormatException(string exception)
        {
            return string.Format("<div style=\"border:1px solid; padding:10px; background-color:yellow;\">{0}</div>", exception);
        }
    }
}

疑问:

既然我们说Response.End将引发一个ThreadAbortException,但为何直接调用Response.End的时候并不会出现异常页面呢?但是我们在页面上直接使用Thread.CurrentThread.Abort(); 却会出现异常页面,请问这是为什么呢?

posted on 2009-06-28 03:38  volnet(可以叫我大V)  阅读(883)  评论(0编辑  收藏  举报

使用Live Messenger联系我
关闭