关于Ajax.net的异常处理机制

来源:互联网 发布:感觉人生没有意义 知乎 编辑:程序博客网 时间:2024/05/16 06:15

最近被Ajax.net的异常处理机制折磨得够呛,最后终于从MS的技术支持那里得到了初步的答案,赶快记下来。

ASP.NET中的异常处理:
当一个异常在调用堆栈中没有被处理,也没有被框架代码处理时,我们说这个异常未处理,它将被ASP.NET捕获,ASP.NET对此未处理错误的处理方法是显示一个页面,列出该未处理异常的详细情况。
有两个在异常未处理时将被ASP.NET调用的事件:
Page_Error event,它提供捕获在Page级别发生错误的方法。
Application_Error event,它提供捕获在代码中的任何地方发生错误的方法。该事件的范围是整个应用程序,这使它成为添加日志代码的一个理想地方。
这两个事件的执行顺序是——先执行Page_Error,后执行Application_Error。如果希望在Page_Error中处理过的错误就不要再在Application_Error中处理,我们可以在Page_Error中处理错误之后,使用Server.ClearError方法清除最后一个错误,避免再调用Application_Error。

ASP.NET AJAX UpdatePanel的异常处理:
您可以使用Reflector反编译UpdatePanel控件可以查看其实现代码发现,放在UpdatePanel控件上的异常已经在RequestManager类的OnPageError中已经处理掉了,所以您在Application_Error无法捕获UpdatePanel中的错误做进一步的处理,详细的解释如下:
UpdatePanel控件的RenderChildren(HtmlTextWriter):Void方法
protected override void RenderChildren(HtmlTextWriter writer)
{
    if (this._asyncPostBackMode)
    {
        if (this._rendered)
        {
            return;
        }
        HtmlTextWriter writer2 = new HtmlTextWriter(new StringWriter(CultureInfo.CurrentCulture));
        base.RenderChildren(writer2);
        PageRequestManager.EncodeString(writer, "updatePanel", this.ClientID, writer2.InnerWriter.ToString());
    }
    else
    {
        writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
        if (this.RenderMode == UpdatePanelRenderMode.Block)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
        }
        else
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Span);
        }
        base.RenderChildren(writer);
        writer.RenderEndTag();
    }
    this._rendered = true;
}
从这个方法中您可以看到在AJAX异步处理中调用了PageRequestManager.EncodeString(writer, "updatePanel", this.ClientID, writer2.InnerWriter.ToString());方法,接着查找PageRequestManager类,您可以发现该类中有OnPageError(object sender,EventArgs e)事件处理器,并且在PageRequestManager类的OnInit初始化事件处理器中登记了OnPageError的事件处理器,从这里可以看出当UpdatePanel上的控件发生异常时,UpdatePanel本身将会把它处理掉,您在Application_Error也就无法捕获到了。
PageRequestManager类的OnInit方法:
internal void OnInit()
{
    if (this._owner.EnablePartialRendering && !this._owner._supportsPartialRenderingSetByUser)
    {
        IHttpBrowserCapabilities browser = this._owner.IPage.Request.Browser;
        bool flag = ((browser.W3CDomVersion >= MinimumW3CDomVersion) && (browser.EcmaScriptVersion >= MinimumEcmaScriptVersion)) && browser.SupportsCallback;
        if (flag)
        {
            flag = !this.EnableLegacyRendering;
        }
        this._owner.SupportsPartialRendering = flag;
    }
    if (this._owner.IsInAsyncPostBack)
    {
        this._owner.IPage.Error += new EventHandler(this.OnPageError);
    }
}
PageRequestManager类的OnPageError方法:
private void OnPageError(object sender, EventArgs e)
{
    Exception lastError = this._owner.IPage.Server.GetLastError();
    this._owner.OnAsyncPostBackError(new AsyncPostBackErrorEventArgs(lastError));
    string asyncPostBackErrorMessage = this._owner.AsyncPostBackErrorMessage;
    if (string.IsNullOrEmpty(asyncPostBackErrorMessage) && !this._owner.Control.Context.IsCustomErrorEnabled)
    {
        asyncPostBackErrorMessage = lastError.Message;
    }
    int httpCode = GetHttpCodeForException(lastError);
    bool flag = false;
    if (this._owner.AllowCustomErrorsRedirect && this._owner.Control.Context.IsCustomErrorEnabled)
    {
        if (!this.CustomErrorsSectionHasRedirect(httpCode))
        {
            flag = true;
        }
    }
    else
    {
        flag = true;
    }
    if (flag)
    {
        this._owner.IPage.Response.Clear();
        EncodeString(this._owner.IPage.Response.Output, "error", httpCode.ToString(CultureInfo.InvariantCulture), asyncPostBackErrorMessage);
        this._owner.IPage.Response.End();
    }
}

希望上述解释能够给您一些帮助。

Jasson Wang
在线技术支持工程师
微软全球技术支持中心
 

原创粉丝点击