30

Web API'm var MVC 4 Web API çerçevesini kullanarak çalışıyorum. Bir istisna varsa, şu anda yeni bir HttpResponseException atıyorum. yani:Web API'sinde özel hata nesneleri döndürün

if (!Int32.TryParse(id, out userId)) 
    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid id")); 

Bu sadece {"message":"Invalid id"}

ben daha ayrıntılı bir nesne döndürerek istisnalara bu yanıt üzerine daha fazla kontrol elde etmek istiyorum olan müşteriye bir nesne döndürür.

Böyle bir şeyi nasıl yapacağım? Hata nesnesini serileştirmenin ve yanıt mesajında ​​ayarlamanın en iyi yolu mu?

Ben de ModelStateDictionary içine biraz baktım ve bir "hack" bu bit ile geldi, ama yine de temiz bir çıkış değil:

var msd = new ModelStateDictionary(); 
msd.AddModelError("status", "-1"); 
msd.AddModelError("substatus", "3"); 
msd.AddModelError("message", "invalid stuff"); 
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, msd)); 

düzenlemek
bir benziyor Özel HttpError ihtiyacım olan şey.

iş katmanı için özel bir istisna sınıf oluşturun:

Bu
var error = new HttpError("invalid stuff") {{"status", -1}, {"substatus", 3}}; 
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, error)); 

cevap

9

ben bu hile olacaktır düşünüyorum ... benim iş katmanından o genişletilebilir yapmak için şimdi, hileye neden olabilir
public class MyException: Exception 
{ 
    public ResponseStatus Status { get; private set; } 
    public ResponseSubStatus SubStatus { get; private set; } 
    public new string Message { get; private set; } 

    public MyException() 
    {} 

    public MyException(ResponseStatus status, ResponseSubStatus subStatus, string message) 
    { 
     Status = status; 
     SubStatus = subStatus; 
     Message = message; 
    } 
} 

MyException örneğinden HttpError oluşturmak için statik bir yöntem oluşturun.

public static HttpError Create<T>(MyException exception) where T:Exception 
    { 
     var properties = exception.GetType().GetProperties(BindingFlags.Instance 
                 | BindingFlags.Public 
                 | BindingFlags.DeclaredOnly); 
     var error = new HttpError(); 
     foreach (var propertyInfo in properties) 
     { 
      error.Add(propertyInfo.Name, propertyInfo.GetValue(exception, null)); 
     } 
     return error; 
    } 

Şu anda genel bir istisna işleyicisi için özel bir özellik vardır: Ben Create güncellenmesi w/o yüzden MyException özellikler ekleyebilirsiniz ve her zaman onları geri döndü burada yansıma kullanıyorum. tip MyException tüm istisnalar burada ele alınacaktır: Bu planı delikler buldukça

public class ExceptionHandlingAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    { 
     var statusCode = HttpStatusCode.InternalServerError; 

     if (context.Exception is MyException) 
     { 
      statusCode = HttpStatusCode.BadRequest; 
      throw new HttpResponseException(context.Request.CreateErrorResponse(statusCode, HttpErrorHelper.Create(context.Exception))); 
     } 

     if (context.Exception is AuthenticationException) 
      statusCode = HttpStatusCode.Forbidden; 

     throw new HttpResponseException(context.Request.CreateErrorResponse(statusCode, context.Exception.Message)); 
    } 
} 

Ben bu biraz daha güncelleme ile uğraşmak gerekir.

+3

Neden Message özelliğini saklıyorsunuz? Tabanı aramak ve mesajı bu şekilde iletmek daha güvenli olmaz mıydı? – Andy

2

Aşağıdaki makaleye göz atın. Web api istisnaları ve hata mesajları üzerinde kontrol kazanmanıza yardımcı olacaktır: Web Api, HttpError, and the Behavior of Exceptions

+1

Teşekkürler. Bu, yaptığım şeye benzer - özel bir ExceptionFilterAttribute oluşturuluyor – earthling

+3

Bu site artık mevcut değil – TravisO

39

Bu cevaplar olması gerekenden daha karmaşıktır.

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     config.Filters.Add(new HandleApiExceptionAttribute()); 
     // ... 
    } 
} 

public class HandleApiExceptionAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    { 
     var request = context.ActionContext.Request; 

     var response = new 
     { 
      //Properties go here... 
     }; 

     context.Response = request.CreateResponse(HttpStatusCode.BadRequest, response); 
    } 
} 

Tek ihtiyacınız olan bu. Ayrıca güzel ve kolay test:

[Test] 
public async void OnException_ShouldBuildProperErrorResponse() 
{ 
    var expected = new 
    { 
     //Properties go here... 
    }; 

    //Setup 
    var target = new HandleApiExceptionAttribute() 

    var contextMock = BuildContextMock(); 

    //Act 
    target.OnException(contextMock); 

    dynamic actual = await contextMock.Response.Content.ReadAsAsync<ExpandoObject>(); 

    Assert.AreEqual(expected.Aproperty, actual.Aproperty); 
} 

private HttpActionExecutedContext BuildContextMock() 
{ 
    var requestMock = new HttpRequestMessage(); 
    requestMock.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration()); 

    return new HttpActionExecutedContext() 
    { 
     ActionContext = new HttpActionContext 
     { 
      ControllerContext = new HttpControllerContext 
      { 
       Request = requestMock 
      } 

     }, 
     Exception = new Exception() 
    }; 
} 
+0

Uygun yanıt – xingyu

+0

da dahil olmak üzere +1 System.Net.Http'yi kullandığınızdan emin olun; – Sal

+0

Bu, en iyi cevaptır. Daha sağlam ve uygulanması kolay.Benim varyasyonda, anonim nesnede, hata ayıklama için istisna mesajıyla ve diğer yararlı ipuçlarıyla bazı özellikler ekledim. Teşekkürler! –