2

Ich versuche benutzerdefinierte Fehlerantworten von web.api zurückzugeben. Lass es einfach String "Oops!" als JSON formatiert sein. Also habe ich einfach delegierenden Handler, die Fehlerreaktionen wie folgt ersetzt:Inhalt fehlt für 404 Antworten

public class ErrorMessageHandler : DelegatingHandler 
{ 
    protected override async Task<HttpResponseMessage> SendAsync(
     HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     var response = await base.SendAsync(request, cancellationToken); 

     if (response.IsSuccessStatusCode) 
      return response; 

     var formatter = new JsonMediaTypeFormatter(); 
     var errorResponse = request.CreateResponse(response.StatusCode, "Oops!", formatter); 
     return errorResponse; 
    } 
} 

Weiter stelle ich sicher, dass dies die einzige Message-Handler in der Pipeline:

httpConfig.MessageHandlers.Clear(); 
httpConfig.MessageHandlers.Add(new ErrorMessageHandler()); 

// Only default route 
httpConfig.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 

app.UseWebApi(httpConfig); // OWIN self-hosting 

Controller ist auch einfachste:

public class ValuesController : ApiController 
{ 
    public IHttpActionResult Get(int id) 
    { 
     if (id == 42) 
     return Ok("Answer to the Ultimate Question of Life, the Universe, and Everything"); 

     return NotFound(); 
    } 
} 

Und hier geht interessant:

  • /api/values/42 gibt mir 200 Antwort mit String-Wert
  • /api/values/13 gibt mir 404-Antwort mit meinem benutzerdefinierten "Oops!" String
  • /api/values/42/missing mir leer 404 Antwort

Der letzte Fall gibt, ist mein Problem. Wenn ich einen Haltepunkt in der letzten Zeile des delegierenden Handlers einstelle, sehe ich klar, dass errorResponseObjectContent<string> mit dem korrekten Wert enthält. Aber warum wird dieser Wert später weggeräumt?

+0

Damit Sie sicher sind, dass „/ api/Werte/42/fehlt“ trifft Handler ? Ich habe das in meiner Umgebung getestet (die nicht die gleiche ist wie deine, aber trotzdem) und für mich wird dieser Handler vollständig umgangen und die Antwort wird von IIS geliefert. – Evk

+0

Vielleicht ein Routing-Problem? Ich muss etwas lesen, aber vielleicht wird der 'DelegierendeHandler' ausgeführt, aber ein Downstream-Event quetscht die Antwort aufgrund der unbekannten Route? Es scheint, dass 'HttpRoutingDispatcher' nach dem benutzerdefinierten Handler ausgeführt wird, wie in [Asp.Net docs] (https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/http-message-handlers). – claylong

+0

@Evk ja, ganz sicher. Handler erhält eine Antwort mit 'HttpError', die besagt, dass für diese Anfrage keine Routendaten gefunden wurden. Dann wird diese Antwort durch die neue 'errorResponse' ersetzt und in die Pipeline zurückgegeben (ich nehme an, sie sollte auf 'HttpServer' gehen). Vielleicht ist es ein Problem? –

Antwort

2

Der Grund ist dieser Code in HttpMessageHandlerAdapter.InvokeCore (also im Grunde in UseWebApi Middleware):

response = await _messageInvoker.SendAsync(request, cancellationToken); 
// ... 
if (IsSoftNotFound(request, response)) { 
     callNext = true; 
} 
else { 
    // ... 
} 

Wo IsSoftNotFound ist:

private static bool IsSoftNotFound(HttpRequestMessage request, HttpResponseMessage response) 
{ 
    if (response.StatusCode == HttpStatusCode.NotFound) 
    { 
     bool routingFailure; 
     if (request.Properties.TryGetValue<bool>(HttpPropertyKeys.NoRouteMatched, out routingFailure) 
      && routingFailure) 
     { 
      return true; 
     } 
    } 
    return false; 
} 

Also im Grunde bei "weichen" 404, wo „soft "bedeutet, dass keine Route übereinstimmt (und durch die Eigenschaft mit einem bestimmten Schlüssel in request.Properties angezeigt wird) - Middleware ruft eine nächste Komponente auf. Sonst - wird nur Antwort senden.

Diese IsSoftDelete gilt für Ihren Fall (weil in der Tat keine Route übereinstimmt) und die nächste Komponente (hatte keine Zeit, um herauszufinden, was das wirklich ist) löscht Ihre Antwort Inhalt.

zu „reparieren“ dieses Problem - entfernen Eigenschaft mit diesem Schlüssel von der Anfrage nach Aufforderung durch vorherige Handler behandelt wurde:

public class ErrorMessageHandler : DelegatingHandler { 
    protected override async Task<HttpResponseMessage> SendAsync(
     HttpRequestMessage request, CancellationToken cancellationToken) { 
     var response = await base.SendAsync(request, cancellationToken); 

     if (response.IsSuccessStatusCode) 
      return response; 

     // here, can also check if 404 
     request.Properties.Remove(HttpPropertyKeys.NoRouteMatched); 
     var formatter = new JsonMediaTypeFormatter(); 
     var errorResponse = request.CreateResponse(response.StatusCode, "Oops!", formatter); 
     return errorResponse; 
    } 
} 
+0

Oh mein Gott! Ich überprüfte alles, einschließlich HttpServer, aber das Problem war in der Tat auf der anderen Seite. Ich werde mehr darüber nachdenken, warum sie dieses seltsame "weiche nicht gefundene" Verhalten implementiert haben. Danke vielmals! –

+0

@SergeyBerezovskiy Wenn Sie herausfinden, was ist das weiche nicht gefunden ist über - bitte hier kommentieren oder neue Antwort vielleicht hinzufügen, da würde mich interessieren, auch zu wissen. – Evk

Verwandte Themen