.net自定義錯誤頁面實現升級篇

猴子哥發表於2018-05-15

  問題描述:

  在上一篇博文 “.net自定義錯誤頁面實現” 中已經介紹了在.net中如何實現自定義錯誤頁面實現(有需要者可以去上一篇博文了解),單純按照上一篇博文那樣設定,能夠實現所有請求的異常自定義跳轉,但是這樣又會產生一個問題:當通過ajax提交請求獲取介面提交請求,如果出現未處理的異常也會被重定向到自定義錯誤頁面。

  針對ajax請求或者介面請求,這樣返回一個重定向頁面,使用者體驗顯然不是太友好,針對這個問題,下面簡單總結一下我自己的想法和解決方案,當然不一定科學和合理,所以也希望有大牛多多指點。

  解決思路,我想到的有二:
解決方案一:
  從物理結構上分割,將web專案嚴格分割成兩個專案(當然可根據需要繼續細分):網站(只有網站頁面資源等內容)、介面(包括網站的所有資料邏輯處理,頁面的資料請求互動都是直接同介面互動(js技術)),
  只是網站專案按照上一篇博文方式設定自定義錯誤頁面方式,這樣是能夠解決問題,專案也會更加的清晰,也有很多公司的專案就是按照這種方式(尤其是webApp),
  但是在實際專案中,很多專案是沒有達到這種嚴格區分的,所以下面的解決方案二,將介紹一個更通用的方式

解決方法二:

  解決思路是:將上一篇博文 .net自定義錯誤頁面實現 與 上上一篇博文 .net捕捉全域性未處理異常的3種方式 結合使用,並在實際開發中嚴格約定(出了url地址請求以外的其他請求都通過post請求實現互動),在撲捉到異常時,如果是post請求,處理異常,並清除異常。具體以步驟如下:
  第一步:定義一個請求處理結果資料MODEL,程式碼如下:
  

    /// <summary>
    /// 請求結果MRequestResult
    /// </summary>
    public class MRequestResult
    {
        /// <summary>
        /// 請求結果編碼(是一個列舉值)
        /// </summary>
        private RequestResultCodeEnum requestResultCode;

        /// <summary>
        /// 處理結果具體的返回值
        /// </summary>
        private object resultValue;

        /// <summary>
        /// 請求結果編碼(是一個列舉值)
        /// </summary>
        public RequestResultCodeEnum RequestResultCode
        {
            get
            {
                return this.requestResultCode;
            }

            set
            {
                this.requestResultCode = value;
            }
        }

        /// <summary>
        /// 處理結果具體的返回值
        /// </summary>
        public object ResultValue
        {
            get
            {
                return this.resultValue;
            }

            set
            {
                this.resultValue = value;
            }
        }
    }


    /// <summary>
    /// 請求結果編碼列舉值()
    /// </summary>
    public enum RequestResultCodeEnum
    {
        /// <summary>
        ///  請求成功
        /// </summary>
        Success = 1,

        /// <summary>
        /// 請求失敗
        /// </summary>
        Fail = -1,
    }

 

 

第二步:按照 上一篇博文: .net自定義錯誤頁面實現的步驟,配置好自定義錯誤頁面相關配置操作

第三步:按照 上上一篇博文:.net捕捉全域性未處理異常的3種方式 的步驟實現全域性異常為處理相關操作設定

第四步:在撲捉全域性未處理的異常中,新增上針對post請求的異常處理過濾(直接輸入封裝後的),具體程式碼如下:

  /// <summary>
        /// 異常處理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void context_Error(object sender, EventArgs e)
        {
            //此處處理異常
            HttpContext ctx = HttpContext.Current;
            HttpResponse response = ctx.Response;
            HttpRequest request = ctx.Request;

            //獲取到HttpUnhandledException異常,這個異常包含一個實際出現的異常
            Exception ex = ctx.Server.GetLastError();
            //實際發生的異常
            Exception iex = ex.InnerException;

            //// 異常日誌落地
            //// 異常日誌落地包括:記錄異常文字檔案日誌、或者記錄異常日誌資料庫等等(根據實際專案需要做記錄)

            //// 獲取請求方法
            string httpMethod = request.HttpMethod;
            //// 如果是POST請求,那麼是以下請求之一
            //// ajax介面請求
            //// form表單提交
            //// 這種情況的異常,不用跳轉至自已的異常錯誤頁面,直接返回對應系統異常
            if (httpMethod.ToUpper() == "POST")
            {
                //// 構建返回物件值
                MRequestResult requestResultM = new MRequestResult();
                requestResultM.RequestResultCode = RequestResultCodeEnum.Fail;
                requestResultM.ResultValue = "系統異常,請聯絡管理員!";

                response.Write(JsonConvert.SerializeObject(requestResultM, Formatting.Indented));
                ctx.Server.ClearError();//處理完及時清理異常
            }
        }

 

程式碼例項:

ajax請求方法及其邏輯處理例項程式碼:

    $(function () {
        $.ajax({
            async: true,
            type: "post",
            url: "../ActionTestResult/ContentResultTest",
            data: "name=xu",
            success: function (resultValue) {

                if (resultValue) {
                    //// 解析處理結果
                    var resultObj = $.parseJSON(resultValue);

                    //// 當RequestResultCode==1 說明該請求成功
                    ////(備註:並不代表處理成功,具體是否處理成功需要通過ResultValue的值根據介面約定解析做相應的邏輯處理)
                    if (resultObj["RequestResultCode"] == 1) {
                        //// 自定義請求成功邏輯處理
                        //// 通過解析具體的ResultValue的值做相應的邏輯處理.....
                        if (resultObj["ResultValue"]) {
                            var doResult = resultObj["ResultValue"].split(`^`);
                            if (doResult && doResult.length > 1) {
                                if (doResult[0] == 1) {
                                    //// 說明處理成功,做相應的邏輯處理
                                    alert("處理成功!");
                                } else {
                                    //// 處理失敗
                                    alert(doResult[1]);
                                }

                            } else {
                                alert("操作失敗!");
                            }

                        } else {
                            alert("未知結果");
                        }

                    } else {
                        //// 說明請求異常
                        //// 自定義邏輯處理
                        alert(resultObj["ResultValue"]);
                    }
                } else {
                    //// 自定義邏輯處理
                    alert("操作失敗!");
                }

                console.log(resultValue);
            },
            error: function (data) {
                //// 自定義邏輯處理
                alert("系統異常,請聯絡管理員。電話:8888888");
                console.log(data);
            }
        });
    });

ajax對應的後臺請求接受例項程式碼:

        /// <summary>
        /// 測試
        /// </summary>
        /// <returns></returns>
        public ContentResult ContentResultTest(string name)
        {
            //// 構建請求處理結果Model
            MRequestResult requestResultM = new MRequestResult() { RequestResultCode = RequestResultCodeEnum.Success };

            //// 業務處理結果
            string doResult = string.Empty;

            //// 本次自作簡單的引數非空判斷,只一個示例
            //// 處理結果本例中也只是通過^連結表示,在實際處理過程中,可以將結果通過一個Json字串
            if (string.IsNullOrEmpty(name))
            {
                doResult = "-1^操作失敗:名稱不能為空!";
            }
            else
            {
                ///// 其他自定義業務邏輯處理,此處省略.....
                doResult = "1^操作成功";
            }

            requestResultM.ResultValue = doResult;

            //// 返回結果
            return Content(JsonConvert.SerializeObject(requestResultM, Formatting.Indented));

        }

 

是不是覺得說的有點繞,本人表述能力有限,不懂的評論交流。
最後:個人能力有限也許該解決方式並不友好,有更好的解決方法,也歡迎留言交流,多多指點,多多指教

相關文章