2013-07-11 25 views
6

Buduję usługę RESTful przy użyciu interfejsu API sieci Web Microsoft ASP.NET.ASP.NET Web API usuwające HttpError z odpowiedzi

Mój problem dotyczy HttpErrors, które Web API wyrzuca użytkownikowi, gdy coś pójdzie nie tak (np. 400 Bad Request lub 404 Not Found).

Problemem jest to, że nie chcę, aby uzyskać zserializowaną httpError w treści odpowiedzi, gdyż czasami dostarcza zbyt dużo informacji, dlatego narusza ona OWASP zasady bezpieczeństwa, na przykład:

Zapytanie:

http://localhost/Service/api/something/555555555555555555555555555555555555555555555555555555555555555555555 

w odpowiedzi dostaję 400 oczywiście, ale z następującymi informacjami Treść:

{ 
"$id": "1", 
"Message": "The request is invalid.", 
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'MyNamespaceAndMethodHere(Int32)' in 'Service.Controllers.MyController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter." 
} 

Coś jak to wskazuje, że nie tylko moim WebServic e jest oparty na technologii ASP.NET WebAPI (co nie jest tak źle), ale także daje pewne informacje o moich nazw, nazw metod, parametrów itp

próbowałem ustawić IncludeErrorDetailPolicy w Global.asax

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never; 

Tak, to jakoś dobrze, teraz wynik nie zawiera sekcji MessageDetail, ale nadal nie chcę w ogóle uzyskać tego HttpError.

Zbudowałem również mój własny DelegatingHandler, ale ma on również wpływ na 400 i 404, które sam generuję w kontrolerach, czego nie chcę.

Moje pytanie brzmi: Czy istnieje jakiś dogodny sposób na pozbycie się serializowanego HttpError z treści odpowiedzi? Wszystko, co chcę, aby użytkownik wrócił po złe żądania, to kod odpowiedzi.

Odpowiedz

1

Co z wykorzystaniem niestandardowego IHttpActionInvoker? Zasadniczo wystarczy wysłać pustą wiadomość HttpResponseMessage.

Oto bardzo prosty przykład:

public class MyApiControllerActionInvoker : ApiControllerActionInvoker 
{ 
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) 
    { 
     var result = base.InvokeActionAsync(actionContext, cancellationToken); 

     if (result.Exception != null) 
     { 
      //Log critical error 
      Debug.WriteLine("unhandled Exception "); 

      return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError)); 
     } 
     else if (result.Result.StatusCode!= HttpStatusCode.OK) 
     { 
      //Log critical error 
      Debug.WriteLine("invalid response status"); 

      return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(result.Result.StatusCode)); 
     } 


     return result; 
    } 
} 

W Global.asax

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new MyApiControllerActionInvoker()); 

Inną ważną rzeczą, można zrobić, nie związane z Web API, jest usunięcie nadmiernego ASP.NET & Nagłówki HTTP usług IIS. Here to dobre wytłumaczenie.

+0

Cóż, myślę, że to byłoby dobre, ale w mojej aplikacji zwracam własne HttpResponseMessages, czasami jako 400 Bad Request, na przykład, jeśli ktoś chce wstawić nowy rekord do mojej bazy danych, używa on metody kontrolera PostNewRecord. Rekord, który wstawia, przechodzi przez walidację, która jeśli wykryje, że brakuje niektórych pól, kontroler zwróci Złe żądanie z moją własną wiadomością, że niektóre pola były puste. W twoim rozwiązaniu MyApiControllerActionInvoker przechwyci tę odpowiedź i usunie moją wiadomość, której nie chcę. Chcę tylko usunąć wiadomości generowane przez Web API. –

+0

+1 dla połączonego artykułu. Świetnie czytaj ponownie: nagłówki –

1

Uważam, że twoje podejście do korzystania z obsługi komunikatów jest poprawne, ponieważ niezależnie od komponentu w potoku Web API, który ustawia kod statusu na 4xx, program obsługi wiadomości może wyczyścić treść odpowiedzi. Jednak chcesz rozróżnić te, które jawnie ustawiłeś, w porównaniu z ustawionymi przez inne komponenty. Oto moja sugestia i przyznaję, że jest trochę hacky. Jeśli nie znajdziesz lepszego rozwiązania, spróbuj tego.

W swoich klasach ApiController, kiedy rzucasz HttpResponseException, ustaw flagę we właściwościach żądania, na przykład tak.

Request.Properties["myexception"] = true; 
throw new HttpResponseException(...); 

W module obsługi komunikatów sprawdź właściwość i nie usuwaj treści odpowiedzi, jeśli właściwość została ustawiona.

var response = await base.SendAsync(request, cancellationToken); 

if((int)response.StatusCode > 399 && !request.Properties.Any(p => p.Key == "myException")) 
    response.Content = null; 

return response; 

Można zapakować to nieco ładnie dodając metodę rozszerzenia do HttpRequestMessage tak, że ani ApiController ani obsługi wiadomość wie nic o zakodowanej smyczkowy „myException”, który używam powyżej.

+0

To oczywiście działa, ale jest, jak powiedziałeś, raczej naprawione, niż rozwiązanie długoterminowe. –