標籤:管理員 構造 代碼 https direct 初始化 each ring 狀態
1 向用戶端發送錯誤訊息
使用throw new HttpResponseException()向用戶端拋出錯誤資訊。
HttpResponseException包含兩個重載的建構函式,其中一個是建構函式參數類型為HttpResponseMessage,通過其設定狀態代碼,錯誤訊息短語以及訊息體內容來向用戶端拋出比較詳細的錯誤資訊。另一個參數類型為HttpStatusCode,只能設定狀態代碼。
2自訂異常過濾器
擴充IExceptionFilter來定義異常過濾器。異常過濾器不會捕獲類型為HttpResponseException的異常,下面的異常也無法被異常過濾器捕獲:
1)controller構造器拋出的異常
2)訊息處理器拋出的異常
3)路由過程中拋出的異常
4)響應內容序列化與還原序列化過程中拋出的異常
程式碼範例:
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { if (context.Exception!=null) { LogHelper.LogError(context.Exception); } } }
3 擴充ExceptionHandler和ExceptionLogger
擴充ExceptionHandler可以捕獲大部分異常,包括一些無法被異常過濾器捕獲的異常。但是HttpResponseException類型的異常不會被捕獲。
範例程式碼:
/// <summary> /// 自訂的例外處理常式 /// </summary> public class GlobalExceptionHandler : ExceptionHandler { /// <summary> /// 處理異常 /// </summary> /// <param name="context"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public override Task HandleAsync(ExceptionHandlerContext context,CancellationToken cancellationToken) { if (!ShouldHandle(context)) { return Task.FromResult(0); } context.Result = new ErrorResult { Request = context.ExceptionContext.Request, Content = "呀! 有異常,請聯絡管理員" }; return Task.FromResult(0); } /// <summary> /// 判斷是否應該處理 /// 後期擴充,重寫方法可過濾掉不需處理的異常 /// </summary> /// <param name="context"></param> /// <returns></returns> public override bool ShouldHandle(ExceptionHandlerContext context) { return true; } private class ErrorResult : IHttpActionResult { public HttpRequestMessage Request { get; set; } public string Content { get; set; } public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError); response.Content = new StringContent(Content); response.RequestMessage = Request; return Task.FromResult(response); } } }public class GlobalExceptionLogger : ExceptionLogger { public override Task LogAsync(ExceptionLoggerContext context,CancellationToken cancellationToken) { if (!ShouldLog(context)) { return Task.FromResult(0); } if (context.Exception != null) { string msg = ClientInfoAnalysis.GetClientInfo(); LogHelper.LogError(context.Exception, msg); } return Task.FromResult(0); } /// <summary> /// 判斷是否應記錄異常 /// 後期重寫此方法,可過濾掉不需要記錄的異常資訊 /// </summary> /// <param name="context"></param> /// <returns></returns> public override bool ShouldLog(ExceptionLoggerContext context) { if ((context.Exception is System.Web.HttpException)) { return false; } return true; }}public static class WebApiConfig { public static void Register(HttpConfiguration config) { // 載入log4net設定檔 LogConfigLoading.Load(AppSettings.Log4netPathForWeb); // 載入Web API服務 config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(AppSettings.ServicesLocation)); // 全域異常資訊處理 config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); // 全域異常記錄 config.Services.Add(typeof(IExceptionLogger), new GlobalExceptionLogger());}}
4某些異常無法被捕獲的異常
問題描述
對於在服務載入過程中的異常,無法通過異常過濾器,即實現了System.Web.Http.Filters.IExceptionFilter介面的過濾器來捕獲,也不能通過註冊ExceptionLogger來達到目的。解決方案如下:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { try { config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation)); } catch (Exception ex) { LogHelper.Error(ex); }//其他代碼}}
其中ServiceAssembliesResolver為:
public class ServiceAssembliesResolver : DefaultAssembliesResolver { //服務外掛程式路徑 private string path; public ServiceAssembliesResolver(string path):base() { this.path = path; } public override ICollection<Assembly> GetAssemblies() { //獲得已有的服務 ICollection<Assembly> baseAssemblies = base.GetAssemblies(); //初始化 List<Assembly> assemblies = new List<Assembly>(baseAssemblies); //載入每一個服務外掛程式 foreach (string file in Directory.GetFiles(path, "*.dll")) { var controllersAssembly = Assembly.LoadFrom(file); assemblies.Add(controllersAssembly); } return assemblies; } }
但上述方法很可能不起作用,根本原因在於將config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));放入try-catch塊中,若ServiceAssembliesResolver在執行個體化的時候不拋出異常,而是當調用GetAssemblies時拋出異常(例如服務外掛程式隱藏檔夾被刪除),此時無法記錄異常。那麼問題就在於GetAssemblies方法何時被調用,通過跟蹤代碼發現Register中的所有代碼都執行完成才會載入服務。解決辦法是在ServiceAssembliesResolver.GetAssemblies中捕獲異常並記錄下來。
asp.net web api 異常捕獲