現在項目是這樣處理的,如果兄弟們更好的方法,分享給我哦
異常處理:
這裡我寫的是全域捕獲異常,捕獲一些我們漏掉的異常
一般我們都會自訂500和400
在web.config中這樣寫
<customErrors mode="RemoteOnly" defaultRedirect="500"> <error statusCode="500" redirect="500"/> <error statusCode="404" redirect="404"/> </customErrors>
這裡的500和400是路由過去的,在Global中添加
// 500 錯誤 routes.MapRoute("500", "500", new { controller = "SiteStatus", action = "_500" }); // 404 routes.MapRoute("404", "404", new { controller = "SiteStatus", action = "_404" });
對應的,有一個 SiteStatusController,其中包含_500 action和_404 action
在Global中,可以看到預設的異常處理機制
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); }
在mvc項目建立一檔案夾Common放我們公用的類,建立一類AppHandleErrorAttribute繼承HandleErrorAttribute,重寫OnException方法
public class AppHandleErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { // 記日誌 ILogger log = LogManager.GetCurrentClassLogger(); Exception ex = filterContext.Exception; if (ex is WebException) { log.Error("自訂異常(WebException):", ex);
// 表示異常已處理,直接跳到500顯示錯誤訊息 filterContext.ExceptionHandled = true; filterContext.Result = new RedirectToRouteResult("500", new RouteValueDictionary(new { message = ex.Message })); } else { log.Error("系統異常:", ex); } } }
WebAppexception的定義
/// <summary> /// 此異常是後端和前端互動使用,後端可以拋出異常,包含異常的資訊,前端捕獲WebException,並將錯誤資訊顯示給使用者 /// 未捕獲的異常可以在Global中處理(記日誌) /// </summary> [Serializable] public class WebException : ApplicationException { public WebException() { } public WebException(string message) : base(message) { } public WebException(string message, Exception innerException) : base(message, innerException) { } protected WebException(SerializationInfo info, StreamingContext context) : base(info, context) { } }
現在我們把 filters.Add(newHandleErrorAttribute());
換成 filters.Add(new AppHandleErrorAttribute());
AppHandleErrorAttribute 處理之後還是會跳轉到500頁面,500方法的定義
/// <summary> /// 500 /// </summary> public ActionResult _500(string message = "處理您的請求時出錯,請聯絡管理員或稍後重試。") { // 如果是ajax請求我們返回-1024,前台有捕獲 if (Request.IsAjaxRequest()) { return Json(new { Code = -1024 }, JsonRequestBehavior.AllowGet); } else { ViewBag.Message = message; return View(); } }
如果是ajax請求我們return View()不行,那麼我們返回一個json給前端的ajax請求
前端的ajax請求也要處理一下
// 重寫jQuery.ajax使能處理服務端異常,以及處理ModelBase var ajax = jQuery.ajax; jQuery.ajax = function (settings) { // 自訂異常訊息 var exceptionMsg = settings["exceptionMsg"] || "處理您的請求時出錯,請聯絡管理員或稍後重試。"; // 異常跳轉方式 1:彈框, 2:跳轉到錯誤頁面 var redirectType = settings["type"] || 1; // 開啟自動處理Model,預設關閉 var enableModelHandle = settings["enableModelError"] || false; var successCallback = settings["success"]; // 在success中處理,jquery.ajax的error函數好像不能寫,頻繁報錯 settings["success"] = function (model) { // 這裡處理異常(在伺服器,ajax 未捕獲的異常,會返回 -1024) if (model.Code === -1024) { if (redirectType === 1) { alert(exceptionMsg); } else { location.href = "/500"; } } // 不是異常,處理ModelBase else { // 開啟了自動處理Model if (enableModelHandle) { // 現在是直接彈框顯示後端定義的Message alert(model.Message); } // 如果定義了success函數,則調用它,並傳入model libra.isFunction(successCallback) && successCallback.call(null, model); } } // 調用jquery.ajax函數,把我們已經寫好的settings傳過去。 ajax(settings); }
好了,這樣前後台結合一下就基本可以了。
身分識別驗證:
建立一個預設的mvc項目的時候可以看到模版中有的action添加了Authorize特性
[Authorize] public ActionResult ChangePassword() { return View(); }
這個也可以添加在controller上,嫌麻煩的話,可以建立一個BaseController,然後所有的Controller繼承它就可以了。
這裡我們還是在Common中添加一類AppAuthorizeAttribute,繼承AuthorizeAttribute,重寫它的OnAuthorization方法
public class AppAuthorizeAttribute : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { // 過濾不需要驗證的頁面 allowGuestPages.Add("controllerName", "|actionName1|actionName2|"); // 過濾整個控制器用 allowGuestPages.Add("controllerName", "all"); Dictionary<string, string> allowGuestPages = new Dictionary<string, string>(); allowGuestPages.Add("home", "all"); allowGuestPages.Add("onlineuser", "all"); string currentControllerName = MvcUtil.GetControllerName(filterContext.RouteData).ToLower(); string currentActionName = MvcUtil.GetActionName(filterContext.RouteData).ToLower(); string allowActions = string.Empty; if (allowGuestPages.TryGetValue(currentControllerName, out allowActions)) { allowActions = allowActions.ToLower(); if (allowActions == "all" || allowActions.Contains("|" + currentActionName + "|")) { return; } } // 沒有登入,跳到登入頁面 if (!OnlineUser.Instantce.IsLogin()) { filterContext.Result = new RedirectToRouteResult("login", routeValues); } } }
在Global檔案中RegisterGlobalFilters方法再添加一篩選器,如下
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new AppHandleErrorAttribute()); filters.Add(new AppAuthorizeAttribute()); }
好了,大功告成,不用在每個controller加Authorize了。。