2017-08-30 64 views
0

我的webapi中有以下方法。我希望能夠通過例外發布帖子並查看 錯誤。我嘗試使用「返回BadRequest(ex.Message);」由於該方法的返回類型,我得到了錯誤。從web api方法返回異常

我該如何解決這個問題,以便我可以返回實際的錯誤信息?

 // GET api/Articles/News 
     public IEnumerable<ArticlesDto> Get(string category) 
     { 
      IEnumerable<ArticlesDto> articlesByCategory = null; 
      try 
      { 
       if (category == null) 
       { 

       } 

       articlesByCategory = _articlesrepository.Find(category);    
      } 
      catch(Exception ex) 
      { 
       return BadRequest(ex.Message); 
      } 

      return articlesByCategory; 
     } 

回答

1

你在做什麼有幾個問題。我們先來看看他們,然後我們會採取更好的方法。

問題

  1. 不要捕捉Exception類型的異常,然後告訴客戶他們的要求是錯誤的請求。如果您有DivideByZeroException,db沒有找到異常,或者InvalidOperationException或任何其他異常,您會告訴客戶他們的請求不好。這顯然不是真的。
  2. 您的API要求客戶爲您提供一個類別的字符串。只要他們提供它,即使它是「xaoudis垃圾」,他們已經完成了他們應該做的事情:爲您提供一個字符串。現在,您有責任盡力而爲,併爲他們提供結果。結果可能是該類別中的項目列表或錯誤。

返回從網頁API

返回一個域對象(或DTO)的響應正常,但如果你想擁有控制權的響應更精細的水平,那麼使用HttpResponseMessage。下面是一個examplef(請閱讀更多信息代碼中的註釋):

public HttpResponseMessage Get(string category) 
{ 
    // Step 1: First check the obvious issues 
    if (string.IsNullOrWhiteSpace(category)) 
    { 
     return Request.CreateResponse(HttpStatusCode.BadRequest); 
    } 

    try 
    { 
     // The client has sent us a category. Now we have to do our best to 
     // satisfy the request. 

     // Step 2: Optional Step: First check to see if we have the category 
     string cat = _categoryRepository.Get(category); 
     if (string.IsNullOrWhiteSpace(cat)) 
     { 
      var message = new HttpResponseMessage(HttpStatusCode.NotFound); 
      message.Content = new StringContent($"The category with the name {category} was not found."); 
      throw new HttpResponseException(message); 
     } 

     // Step 3: Category exists so let's return the products 
     IEnumerable<ArticlesDto> articlesByCategory = _articlesrepository.Find(category); 

     // Even if the list is empty, we can still return it to tell 
     // the client 0 items were found 
     // for the category. 
     return Request.CreateResponse(HttpStatusCode.OK, articlesByCategory); 
    } 
    catch (Exception ex) 
    { 
     // Something went wrong on our side (NOT the client's fault). So we need to: 
     // 1. Log the error so we can troubleshoot it later 
     // 2. Let the client know it is not their fault but our fault. 
     return Request.CreateResponse(HttpStatusCode.InternalServerError); 
    } 
} 

的Web API 2

隨着Web API 2,你可以像下面這樣做是非常容易和更清潔。請根據您的要求更改代碼。

+0

這是堅實的。它測試每個級別。我會遵循這一點。謝謝 – user2320476

+0

@ user2320476很高興能幫到你。有機會時請閱讀[this](https://stackoverflow.com/help/someone-answers)。 – CodingYoshi

0

可能有一些其他的方式來做到這一點(我不宣稱自己是一個ASP.Net核心專家),但我已經解決了這個問題,下面的方法。首先,定義一個自定義的異常類。目的是,你可以實際上這不考慮任何控制器方法返回類型。而且,拋出異常使得控制流程更加結構化。

public class CustomApiException : Exception 
{ 
    /// <summary> 
    /// Optional application-specific error code returned to the client. 
    /// </summary> 
    public int? ApplicationErrorCode { get; private set; } = null; 

    /// <summary> 
    /// HTTP status code returned to the client. 
    /// </summary> 
    public HttpStatusCode HttpStatusCode { get; private set; } = HttpStatusCode.BadRequest; 

    public CustomApiException() : base() { } 
    public CustomApiException(string message) : base(message) { } 

    public CustomApiException(string message, HttpStatusCode httpStatusCode) : base(message) 
    { 
     HttpStatusCode = httpStatusCode; 
    } 

    public CustomApiException(string message, HttpStatusCode httpStatusCode, int? applicationErrorCode) : base(message) 
    { 
     HttpStatusCode = httpStatusCode; 
     ApplicationErrorCode = applicationErrorCode; 
    } 

    public CustomApiException(string message, int? applicationErrorCode) : base(message) 
    { 
     ApplicationErrorCode = applicationErrorCode; 
    } 
} 

然後定義一個自定義的ExceptionFilterAttribute。請注意,此複製/粘貼片段比您要求的要多一點。例如。取決於開發與生產,它將包括異常的整個堆棧跟蹤(實際上是任何異常,而不僅僅是CustomApiException)。

// todo: turn into async filter. 
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute 
{ 
    private readonly ILogger<ApiExceptionFilterAttribute> _logger; 
    private readonly IHostingEnvironment _env; 

    public ApiExceptionFilterAttribute(ILogger<ApiExceptionFilterAttribute> logger, IHostingEnvironment env) 
    { 
     _logger = logger; 
     _env = env; 
    } 

    public override void OnException(ExceptionContext context) 
    { 
     _logger.LogError(new EventId(0), context.Exception, context.Exception.Message); 

     dynamic errObject = new JObject(); 
     HttpStatusCode statusCode = HttpStatusCode.InternalServerError; // use 500 unless the API says it's a client error 

     if (context.Exception.GetType() == typeof(CustomApiException)) 
     { 
      CustomApiException customEx = (CustomApiException)context.Exception; 
      if (customEx.ApplicationErrorCode != null) errObject.errorCode = customEx.ApplicationErrorCode; 
      errObject.errorMessage = customEx.Message; 
      statusCode = customEx.HttpStatusCode; 
     } 

     if (_env.IsDevelopment()) 
     { 
      errObject.errorMessage = context.Exception.Message; 
      errObject.type = context.Exception.GetType().ToString(); 
      errObject.stackTrace = context.Exception.StackTrace; 
     } 

     JsonResult result = new JsonResult(errObject); 
     result.StatusCode = (int?)statusCode; 
     context.Result = result; 
    } 
} 

最後,將自定義ExceptionFilterAttribute添加到全局ConfigureServices方法中。

public class Startup 
{ 
    // This method gets called by the runtime. Use this method to add services to the container. 
    public void ConfigureServices(IServiceCollection services) 
    { 
     //... 

     // Add framework services. 
     services.AddMvc(options => 
      { 
       options.Filters.Add(typeof(ApiExceptionFilterAttribute)); 
      }); 
    } 

    // ... 
} 

這是一個有點工作,但只有一次性的工作,並且一旦你添加它,功能就非常強大。如果我沒有記錯,我的解決方案是基於這個MS頁面Exception Handling。如果您還有其他問題,這可能會有所幫助。

+0

掛起 - 這看起來像MVC而不是WebAPI,應該'Startup.ConfigureServices'是'WebApiConfig.Register'? –

+0

我認爲這取決於ASP.Net和ASP.Net Core的版本。在本教程中,https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api,它絕對是一個Web API項目,但使用StartUp類和services.UseMvc()。再次,我不聲稱自己是這方面的專家。也許user2320476可以指定他/她正在使用的框架和版本。 – Christoph

+0

這是webapi2而不是.net核心 – user2320476

0

對於你的情況,我認爲丟掉HttpResponseExceptionHttpResponseMessage包含異常消息將工作。流程代碼片段已經過測試。

public IEnumerable<string> Get() 
    { 
     try 
     { 
      throw new InvalidOperationException("Invalid Operation"); 
     } 
     catch(Exception ex) 
     { 
      var res = new HttpResponseMessage(HttpStatusCode.InternalServerError); 
      res.Content = new StringContent(ex.Message); 
      throw new HttpResponseException(res); 
     } 
    } 

有關如何處理例外的WebAPI流程,請參閱this官方指南的詳細信息。希望它對你有幫助。