ServiceStack 錯誤處理

来源:https://www.cnblogs.com/joyswings/archive/2019/03/12/10515896.html
-Advertisement-
Play Games

拋出C#異常 在大多數情況下,您不需要關心ServiceStack的錯誤處理,因為它為拋出C#異常的正常用例提供本機支持,例如: HTTP錯誤C#異常的預設映射 預設C#例外: ArgumentException使用HTTP StatusCode為400 BadRequest返回繼承 NotImpl ...


拋出C#異常

在大多數情況下,您不需要關心ServiceStack的錯誤處理,因為它為拋出C#異常的正常用例提供本機支持,例如:

public object Post(User request) 
{
    if (string.IsNullOrEmpty(request.Name))
        throw new ArgumentNullException("Name");
}

HTTP錯誤C#異常的預設映射

預設C#例外:

  • ArgumentException使用HTTP StatusCode為400 BadRequest返回繼承
  • NotImplementedException或者NotSupportedException 作為405 MethodNotAllowed返回
  • AuthenticationException401 Unauthorized身份返回
  • UnauthorizedAccessException403 Forbidden返回
  • OptimisticConcurrencyException返回409衝突
  • 其他正常的C#異常作為500 InternalServerError返回

可以使用用戶定義的映射擴展此列表Config.MapExceptionToStatusCode

WebServiceException

所有異常都被註入到ResponseStatus響應DTO 屬性中,屬性被序列化到ServiceClient的首選內容類型中,使得錯誤處理變得透明,無論您的首選格式如何 - 即,相同的C#錯誤處理代碼可用於所有ServiceClient。

try 
{
    var client = new JsonServiceClient(BaseUri);
    var response = client.Send<UserResponse>(new User());
} 
catch (WebServiceException webEx) 
{
    /*
      webEx.StatusCode        = 400
      webEx.StatusDescription = ArgumentNullException
      webEx.ErrorCode         = ArgumentNullException
      webEx.ErrorMessage      = Value cannot be null. Parameter name: Name
      webEx.StackTrace        = (your Server Exception StackTrace - in DebugMode)
      webEx.ResponseDto       = (your populated Response DTO)
      webEx.ResponseStatus    = (your populated Response Status DTO)
      webEx.GetFieldErrors()  = (individual errors for each field if any)
    */
}

 

其中StatusCodeStatusDescription是HTTP StatusCode和Description,顯示所有HTTP客戶端看到的頂級HTTP層詳細信息。StatusDescription通常很短,用於指示返回的錯誤類型,預設情況下是拋出的異常類型。HTTP客戶端通常會檢查StatusCode以確定如何在客戶端上處理錯誤。

所有服務客戶端還可以訪問錯誤響應DTO主體中返回的應用程式級錯誤詳細信息,其中ErrorCode包含異常類型,客戶端將檢查以確定和處理異常類型,同時ErrorMessage保存伺服器異常消息它提供了一個人性化的,更長和描述性的錯誤描述,可以顯示給最終用戶。DebugMode中StackTrace使用Server StackTrace填充,以幫助前端開發人員識別錯誤的原因和位置。

如果錯誤引用特定欄位(如欄位驗證異常),則GetFieldErrors()保留每個具有錯誤的欄位的錯誤信息。

可以通過以下各種選項更改這些預設值以提供進一步的自定義錯誤響應:

啟用S​​tackTraces

預設情況下,在響應DTO中顯示StackTraces僅在調試版本中啟用,儘管此行為可以通過以下方式覆蓋:

SetConfig(new HostConfig { DebugMode = true });

錯誤響應類型

拋出異常時返回的錯誤響應取決於是否存在常規命名的{RequestDto}ResponseDTO。

如果存在:

{RequestDto}Response返回,而不管服務方法的響應類型的。如果{RequestDto}ResponseDTO具有ResponseStatus屬性,則會填充它,否則將不返回ResponseStatus(如果{ResponseDto}Response使用[DataContract]/[DataMember]屬性修飾了類和屬性,則還需要對ResponseStatus進行修飾以填充)。

否則:

通過ErrorResponse填充的ResponseStatus屬性返回泛型

服務客戶端透明地處理不同的錯誤響應類型,併為無模式格式,如JSON / JSV /等有返回之間沒有實際明顯的區別ResponseStatus自定義或通用的ErrorResponse-因為它們都輸出電線上的同樣的反應。

自定義例外

最終,所有ServiceStack WebServiceExceptions都只是Response DTO,其中包含一個填充的ResponseStatus,它返回HTTP錯誤狀態。有多種不同的方法可以自定義異常的返回方式,包括:

自定義C#異常到HTTP錯誤狀態的映射

您可以通過以下方式配置為不同的異常類型更改返回的HTTP錯誤狀態:

 

SetConfig(new HostConfig { 
    MapExceptionToStatusCode = {
        { typeof(CustomInvalidRoleException), 403 },
        { typeof(CustomerNotFoundException), 404 },
    }
});

 

返回HttpError

如果你想要對你的HTTP錯誤進行更細粒度的控制,你可以拋出返回一個HttpError,讓你自定義Http HeadersStatus Code和HTTP Response Body以便線上上獲得你想要的內容:

public object Get(User request) 
{
    throw HttpError.NotFound("User {0} does not exist".Fmt(request.Name));
}

 

以上內容線上路上返回404 NotFound StatusCode,是以下方面的簡寫:

new HttpError(HttpStatusCode.NotFound, 
    "User {0} does not exist".Fmt(request.Name)); 

 

具有自定義響應DTO的HttpError

HttpError還可用於返回更結構化的錯誤響應:

var responseDto = new ErrorResponse { 
    ResponseStatus = new ResponseStatus {
        ErrorCode = typeof(ArgumentException).Name,
        Message = "Invalid Request",
        Errors = new List<ResponseError> {
            new ResponseError {
                ErrorCode = "NotEmpty",
                FieldName = "Company",
                Message = "'Company' should not be empty."
            }
        }
    }
};

throw new HttpError(HttpStatusCode.BadRequest, "ArgumentException") {
    Response = responseDto,
}; 

 

實現IResponseStatusConvertible

您還可以通過實現IResponseStatusConvertible介面來覆蓋自定義異常的序列化,以返回您自己填充的ResponseStatus。這是ValidationException允許通過讓ValidationException實現IResponseStatusConvertible介面來自定義Response DTO 方法

例如,這是一個自定義的Exception示例,它返回填充的欄位錯誤:

public class CustomFieldException : Exception, IResponseStatusConvertible
{
  ...
    public string FieldErrorCode { get; set; }
    public string FieldName { get; set; }
    public string FieldMessage { get; set; }

    public ResponseStatus ToResponseStatus()
    {
        return new ResponseStatus {
            ErrorCode = GetType().Name,
            Message = Message,
            Errors = new List<ResponseError> {
                new ResponseError {
                    ErrorCode = FieldErrorCode,
                    FieldName = FieldName,
                    Message = FieldMessage
                }
            }
        }
    }    
}

 

實現IHasStatusCode

除了使用IResponseStatusConvertible自定義C#Exceptions的HTTP Response Body之外,您還可以通過實現IHasStatusCode以下內容來自定義HTTP狀態代碼

public class Custom401Exception : Exception, IHasStatusCode
{
    public int StatusCode 
    { 
        get { return 401; } 
    }
}

 

同樣IHasStatusDescription可以用於自定義StatusDescriptionIHasErrorCode自定義ErrorCode返回的,而不是其異常類型。

覆蓋AppHost中的OnExceptionTypeFilter

您還可以ResponseStatus通過覆蓋OnExceptionTypeFilterAppHost 來捕獲和修改返回的返回值,例如ServiceStack使用它來自定義返回的ResponseStatus以自動為ArgumentExceptions指定的欄位添加自定義欄位錯誤ParamName,例如:

public virtual void OnExceptionTypeFilter(
    Exception ex, ResponseStatus responseStatus)
{
    var argEx = ex as ArgumentException;
    var isValidationSummaryEx = argEx is ValidationException;
    if (argEx != null && !isValidationSummaryEx && argEx.ParamName != null)
    {
        var paramMsgIndex = argEx.Message.LastIndexOf("Parameter name:");
        var errorMsg = paramMsgIndex > 0
            ? argEx.Message.Substring(0, paramMsgIndex)
            : argEx.Message;

        responseStatus.Errors.Add(new ResponseError
        {
            ErrorCode = ex.GetType().Name,
            FieldName = argEx.ParamName,
            Message = errorMsg,
        });
    }
}

 

自定義HTTP錯誤

在任何請求或響應過濾器中,您可以通過發出自定義HTTP響應並結束請求來短路請求管道,例如:

this.PreRequestFilters.Add((req,res) => 
{
    if (req.PathInfo.StartsWith("/admin") && 
        !req.GetSession().HasRole("Admin")) 
    {
        res.StatusCode = (int)HttpStatusCode.Forbidden;
        res.StatusDescription = "Requires Admin Role";
        res.EndRequest();
    }
});

 

在自定義HttpHandler中結束請求使用 res.EndHttpHandlerRequest()

後備錯誤頁面

使用IAppHost.GlobalHtmlErrorHttpHandler用於指定後備HttpHandler的所有錯誤狀態代碼,例如:

public override void Configure(Container container)
{
    this.GlobalHtmlErrorHttpHandler = new RazorHandler("/oops"),
}

 

要獲得更細粒度的控制,請使用IAppHost.CustomErrorHttpHandlers指定自定義HttpHandler以與特定錯誤狀態代碼一起使用,例如:

public override void Configure(Container container)
{
    this.CustomErrorHttpHandlers[HttpStatusCode.NotFound] = 
        new RazorHandler("/notfound");
    this.CustomErrorHttpHandlers[HttpStatusCode.Unauthorized] = 
        new RazorHandler("/login");
}

 

註冊處理服務異常的處理程式

ServiceStack及其API設計提供了一種攔截異常的靈活方法。如果你需要的所有服務異常的單一入口點,您可以將處理程式添加到AppHost.ServiceExceptionHandlerConfigure要處理服務之外發生的異常,您可以設置全局AppHost.UncaughtExceptionHandlers處理程式,例如:

public override void Configure(Container container)
{
    //Handle Exceptions occurring in Services:

    this.ServiceExceptionHandlers.Add((httpReq, request, exception) => {
        //log your exceptions here
        ...
        return null; //continue with default Error Handling

        //or return your own custom response
        //return DtoUtils.CreateErrorResponse(request, exception);
    });

    //Handle Unhandled Exceptions occurring outside of Services
    //E.g. Exceptions during Request binding or in filters:
    this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) => {
         res.Write($"Error: {ex.GetType().Name}: {ex.Message}");
         res.EndRequest(skipHeaders: true);
    });
}

 

非同步異常處理程式

如果您的處理程式需要進行任何非同步調用,則可以使用Async版本:

this.ServiceExceptionHandlersAsync.Add(async (httpReq, request, ex) =>
{
    await LogServiceExceptionAsync(httpReq, request, ex);

    if (ex is UnhandledException)
        throw ex;

    if (request is IQueryDb)
        return DtoUtils.CreateErrorResponse(request, new ArgumentException("AutoQuery request failed"));

    return null;
});

this.UncaughtExceptionHandlersAsync.Add(async (req, res, operationName, ex) =>
{
    await res.WriteAsync($"UncaughtException '{ex.GetType().Name}' at '{req.PathInfo}'");
    res.EndRequest(skipHeaders: true);
});

 

使用自定義ServiceRunner進行錯誤處理

如果您想為不同的操作和服務提供不同的錯誤處理程式,您可以告訴ServiceStack在您自己的自定義IServiceRunner中運行您的服務,在AppHost中實現HandleExcepion事件掛鉤:

public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
    ActionContext actionContext)
{           
    return new MyServiceRunner<TRequest>(this, actionContext); 
}

 

其中MyServiceRunner就是實現你感興趣的,如自定義掛鉤的自定義類:

public class MyServiceRunner<T> : ServiceRunner<T> 
{
    public MyServiceRunner(IAppHost appHost, ActionContext actionContext) 
        : base(appHost, actionContext) {}

    public override object HandleException(IRequest request, 
        T request, Exception ex) {
      // Called whenever an exception is thrown in your Services Action
    }
}

 

 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在虛擬機中安裝CentOS7碰到的問題以及解決方法 1.安裝之後想通過CRT遠程連接獲,輸入ifconfig查看系統ip報錯誤:ifconfig command not found,報此錯誤是由於初次安裝的CentOS是未啟用網路的,所以我們需要啟用網路 2.所以需要打開network,需執行如下命 ...
  • net core 和普通net 發佈沒有什麼不同,只需要在個別地方註意下: 1. 在visual Studio 2017 發佈 2. 把發佈好的文件copy到伺服器上,並新建一個網站,同時要註意選擇無托管代碼 3.此時訪問介面,會報錯,是因為沒有安裝 window server Hosting,它的 ...
  • 今天工作中遇到了一個情景: 前端向後臺發送一個請求,希望後臺返回一組數據,由於後臺返回的數據量很大,希望儘可能壓縮響應的大小 我的想法:後臺將數據(Short的數組)直接轉換成Byte[] 然後將byte[]發送至前端。 傳統的Json是將數據序列化成Json文件在發送到前端,這樣做的好處是處理簡單 ...
  • 系統:WIndows 10 工具:Visual Studio 2017 在寫代碼的過程中,我遇到了這樣的一個問題。如圖 vs錯誤提示是在SqlHelper中有錯,可是怎麼改都不能解決問題。 最後發現是前端往後端傳數據的時候,多寫了一個Id,如圖 在下麵編號中我已經回傳了一個Id的值,就不再需要一個h ...
  • ASP.NET Core 身份驗證及鑒權 目錄 + 項目準備 + 身份驗證 定義基本類型和介面 編寫驗證處理器 實現用戶身份驗證 + 許可權鑒定 思路 編寫過濾器類及相關介面 實現屬性註入 實現用戶許可權鑒定 + 測試 環境 + VS 2017 + ASP.NET Core 2.2 目標 以相對簡單優雅 ...
  • 昨天看碼雲上有兩個項目感覺很好, 可惜竟然不會Git 找了很久看了好多文檔看他寫的都好複雜啊! 在這我給寫出來一點點 1.下載Git https://git-scm.com/download/win 安裝 64-bit Git for Windows Setup. 這個版本。 2.在所需要下載的文件 ...
  • Electron.Net(結合Asp.Net Core)初次使用 ...
  • 最近在研究串口通訊,其中有幾個比較重要的概念,RS-232這種適配於上位機和PC端進行連接,RS-232只限於PC串口和設備間點對點的通信。它很簡單的就可以進行連接,由於串口通訊是非同步的,也就是說你可以同時向兩端或者更多進行數據發送,它們之間的傳輸數據類型是byte,串口通信最重要的參數是波特率、數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...