468 Stimmen

Bewährte Verfahren zur Fehlerrückgabe in ASP.NET Web API

Ich habe Bedenken hinsichtlich der Art und Weise, wie wir Fehler an den Kunden zurückgeben.

Geben wir einen Fehler sofort zurück, indem wir HttpResponseException wenn wir einen Fehler erhalten:

public void Post(Customer customer)
{
    if (string.IsNullOrEmpty(customer.Name))
    {
        throw new HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest) 
    }
    if (customer.Accounts.Count == 0)
    {
         throw new HttpResponseException("Customer does not have any account", HttpStatusCode.BadRequest) 
    }
}

Oder wir sammeln alle Fehler und senden sie an den Kunden zurück:

public void Post(Customer customer)
{
    List<string> errors = new List<string>();
    if (string.IsNullOrEmpty(customer.Name))
    {
        errors.Add("Customer Name cannot be empty"); 
    }
    if (customer.Accounts.Count == 0)
    {
         errors.Add("Customer does not have any account"); 
    }
    var responseMessage = new HttpResponseMessage<List<string>>(errors, HttpStatusCode.BadRequest);
    throw new HttpResponseException(responseMessage);
}

Dies ist nur ein Beispiel-Code, es spielt keine Rolle, entweder Validierung Fehler oder Server-Fehler, ich möchte nur die beste Praxis, die Vor- und Nachteile der einzelnen Ansatz zu kennen.

1voto

Tawab Wakil Punkte 1144

Einige dieser Antworten scheinen ein Relikt der Vergangenheit zu sein. Ich habe die folgende Lösung gefunden, die einfach ist und gut funktioniert. Dies ist in .NET 6 für eine Web-API abgeleitet von ControllerBase .

Anstatt Ausnahmen auszulösen, können Sie die verschiedenen HTTP-Antwortcodes direkt als Objekte zurückgeben, zusammen mit einer genauen Fehlermeldung:

using Microsoft.AspNetCore.Mvc;

[ApiController]
public class MyWebApiController : ControllerBase
{
    [HttpPost]
    public IActionResult Process(Customer customer)
    {
        if (string.IsNullOrEmpty(customer.Name))
            return BadRequest("Customer Name cannot be empty");

        if (!Customers.Find(customer))
            return NotFound("Customer does not have any account");

        // After validating inputs, core logic goes here...

        return Ok(customer.ID);  // or simply "return Ok()" if not returning data
    }
}

Siehe eine Liste der verfügbaren Fehlercodes aquí .

Wann die Fehler zurückgegeben werden sollen (Frage des Auftraggebers), hängt von der jeweiligen Anforderung ab. Wenn Sie Fehler zurückgeben, sobald sie auftreten, vermeiden Sie den Overhead der zusätzlichen Verarbeitung, aber dann muss der Client wiederholt aufrufen, um alle Fehler zu erhalten. Berücksichtigen Sie auch den Standpunkt des Servers, da es zu unerwünschtem Programmverhalten führen kann, die serverseitige Verarbeitung fortzusetzen, wenn ein Fehler aufgetreten ist.

0voto

Thomas Hagström Punkte 3811

Ein kurzes Update zum aktuellen Stand der ASP.NET WebAPI. Die Schnittstelle heißt jetzt IActionResult und die Umsetzung hat sich nicht wesentlich geändert:

[JsonObject(IsReference = true)]
public class DuplicateEntityException : IActionResult
{        
    public DuplicateEntityException(object duplicateEntity, object entityId)
    {
        this.EntityType = duplicateEntity.GetType().Name;
        this.EntityId = entityId;
    }

    /// <summary>
    ///     Id of the duplicate (new) entity
    /// </summary>
    public object EntityId { get; set; }

    /// <summary>
    ///     Type of the duplicate (new) entity
    /// </summary>
    public string EntityType { get; set; }

    public Task ExecuteResultAsync(ActionContext context)
    {
        var message = new StringContent($"{this.EntityType ?? "Entity"} with id {this.EntityId ?? "(no id)"} already exist in the database");

        var response = new HttpResponseMessage(HttpStatusCode.Ambiguous) { Content = message };

        return Task.FromResult(response);
    }

    #endregion
}

0voto

Zablon Punkte 77

Versuchen Sie dies

[HttpPost]
public async Task<ActionResult<User>> PostUser(int UserTypeId, User user)
{
  if (somethingFails)
  {
    // Return the error message like this.
    return new BadRequestObjectResult(new
    {
      message = "Something is not working here"
    });
  }

  return ok();
}

-2voto

Ashish Sahu Punkte 177

Bei den Fehlern, bei denen modelstate.isvalid falsch ist, sende ich den Fehler in der Regel so, wie er vom Code ausgelöst wird. Das ist für den Entwickler, der meinen Dienst nutzt, leicht zu verstehen. Im Allgemeinen sende ich das Ergebnis mit dem folgenden Code.

     if(!ModelState.IsValid) {
                List<string> errorlist=new List<string>();
                foreach (var value in ModelState.Values)
                {
                    foreach(var error in value.Errors)
                    errorlist.Add( error.Exception.ToString());
                    //errorlist.Add(value.Errors);
                }
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest,errorlist);}

Dadurch wird der Fehler an den Client in folgendem Format gesendet, das im Wesentlichen eine Liste von Fehlern ist:

    [  
    "Newtonsoft.Json.JsonReaderException: **Could not convert string to integer: abc. Path 'Country',** line 6, position 16.\r\n   
at Newtonsoft.Json.JsonReader.ReadAsInt32Internal()\r\n   
at Newtonsoft.Json.JsonTextReader.ReadAsInt32()\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter, Boolean inArray)\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)",

       "Newtonsoft.Json.JsonReaderException: **Could not convert string to integer: ab. Path 'State'**, line 7, position 13.\r\n   
at Newtonsoft.Json.JsonReader.ReadAsInt32Internal()\r\n   
at Newtonsoft.Json.JsonTextReader.ReadAsInt32()\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter, Boolean inArray)\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)"
    ]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X