it-swarm.com.de

Fehlerbehandlung (Senden von ex.Message an den Client)

Ich habe eine ASP.NET Core 1.0-Web-API-Anwendung und versuche herauszufinden, wie die Ausnahmemeldung an den Client weitergeleitet wird, wenn eine Funktion, die mein Controller aufruft, Fehler verursacht.

Ich habe so viele Dinge ausprobiert, aber nichts implementiert IActionResult.

Ich verstehe nicht, warum dies keine alltägliche Sache ist, die die Leute brauchen. Wenn es ehrlich gesagt keine Lösung gibt, kann mir jemand sagen warum?

Ich sehe einige Dokumentationen unter Verwendung von HttpResponseException(HttpResponseMessage), aber um dies zu verwenden, muss ich das kompatible Shim installieren. Gibt es eine neue Möglichkeit, diese Dinge in Core 1.0 zu tun?

Hier ist etwas, was ich mit dem Shim versucht habe, aber es funktioniert nicht:

// GET: api/customers/{id}
[HttpGet("{id}", Name = "GetCustomer")]
public IActionResult GetById(int id)
{
    Customer c = _customersService.GetCustomerById(id);
    if (c == null)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NotFound)
        {
            Content = new StringContent("Customer doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
            StatusCode = HttpStatusCode.NotFound

        };

        throw new HttpResponseException(response);

        //return NotFound();
    }
    return new ObjectResult(c);
}

Wenn das HttpResponseException ausgelöst wird, schaue ich auf den Client und kann die Nachricht, die ich sende, im Inhalt nicht finden.

38
Blake Rivell

Hier ist eine einfache Fehler-DTO-Klasse

public class ErrorDto
{
    public int Code {get;set;}
    public string Message { get; set; }

    // other fields

    public override string ToString()
    {
        return JsonConvert.SerializeObject(this);
    }
}

Und dann mit der ExceptionHandler Middleware:

            app.UseExceptionHandler(errorApp =>
            {
                errorApp.Run(async context =>
                {
                    context.Response.StatusCode = 500; // or another Status accordingly to Exception Type
                    context.Response.ContentType = "application/json";

                    var error = context.Features.Get<IExceptionHandlerFeature>();
                    if (error != null)
                    {
                        var ex = error.Error;

                        await context.Response.WriteAsync(new ErrorDto()
                        {
                            Code = <your custom code based on Exception Type>,
                            Message = ex.Message // or your custom message
                            // other custom data
                        }.ToString(), Encoding.UTF8);
                    }
                });
            });
54
Set

Ja, Sie können den Statuscode nach Bedarf ändern:

Ändern Sie den Code in Ihrer CustomExceptionFilterAttribute.cs-Datei wie folgt:

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.Result = new ContentResult
        {
            Content = $"Error: {exception.Message}",
            ContentType = "text/plain",
            // change to whatever status code you want to send out
            StatusCode = (int?)HttpStatusCode.BadRequest 
        };
    }
}

Das wars so ziemlich.

Wenn Sie benutzerdefinierte Ausnahmen haben, können Sie diese auch überprüfen, wenn Sie die ausgelöste Ausnahme aus dem Kontext holen. Anschließend können Sie je nach dem, was in Ihrem Code passiert ist, verschiedene HTTP-Statuscodes senden.

Hoffentlich hilft das.

7
shabbirh

Sie können einen benutzerdefinierten Ausnahmefilter wie unten erstellen

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.Result = new JsonResult(exception.Message);
    }
}

Wenden Sie dann das obige Attribut auf Ihren Controller an.

[Route("api/[controller]")]
[CustomExceptionFilter]
public class ValuesController : Controller
{
     // GET: api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        throw new Exception("Suckers");
        return new string[] { "value1", "value2" };
    }
}
6
cvraman

Wie wäre es, wenn Sie Ihre Aktion vereinfachen, anstatt eine Ausnahme auszulösen und abzufangen, um:

// GET: api/customers/{id}
[HttpGet("{id}", Name = "GetCustomer")]
public IActionResult GetById(int id)
{
    var customer = _customersService.GetCustomerById(id);

    if (customer == null)
    {
        return NotFound("Customer doesn't exist");        
    }

    return Ok(customer);
}

Ich habe einen Blog-Beitrag geschrieben, der einige weitere Optionen enthält, beispielsweise die Rückgabe eines JSON-Objekts anstelle von Text.

2
Paul Hiles

Vielleicht ist das hilfreich. Sie können nur object zurückgeben und zum Beispiel ein BadRequest (HTTP-CODE: 400) mit Ihrem benutzerdefinierten object als aktuellem Parameter senden (ich habe hier nur einen interpolierten String verwendet), aber Sie kann in alles setzen.

Auf Ihrer Client-Seite können Sie diese Fehlersituation beispielsweise mit einem AJAX-Fehlerbehandler abfangen.

// GET: api/TruckFahrerGeoData
[HttpGet]
public object GetTruckFahrerGeoData()
{

    var truckFahrerGeoDataItems = new List<TruckFahrerGeoDataViewModel>();

    var geodataItems = _context.TruckFahrerGeoData;

    foreach (var truckFahrerGeoData in geodataItems)
    {
        GeoTelemetryData geoTelemetryData = JsonConvert.DeserializeObject<GeoTelemetryData>(truckFahrerGeoData.TelemetryData);

        if (geoTelemetryData == null)
        {
            return BadRequest($"geoTelemetryData null for id: {truckFahrerGeoData.Id}");
        }
        TruckFahrerGeoDataViewModel truckFahrerGeoDataViewModel = new TruckFahrerGeoDataViewModel
        {
            Speed = geoTelemetryData.Speed,
            Accuracy = geoTelemetryData.Accuracy,
            TruckAppId = geoTelemetryData.Activity.TruckAppId,
            TruckAuftragStatusId = geoTelemetryData.Activity.TruckAuftragStatusId,
            ClId = geoTelemetryData.Activity.ClId,
            TruckAuftragLaufStatusId = geoTelemetryData.Activity.TruckAuftragLaufStatusId,
            TaskId = geoTelemetryData.Activity.TaskId,
            TruckAuftragWorkflowStatusId = geoTelemetryData.Activity.TruckAuftragWorkflowStatusId
        };

        truckFahrerGeoDataItems.Add(truckFahrerGeoDataViewModel);
    }


    return truckFahrerGeoDataItems;
}

Oder noch sauberer mit IActionResult:

// GET: api/TruckFahrerGeoData
[HttpGet]
public IActionResult GetTruckFahrerGeoData()
{

    var truckFahrerGeoDataItems = new List<TruckFahrerGeoDataViewModel>();

    var geodataItems = _context.TruckFahrerGeoData;

    foreach (var truckFahrerGeoData in geodataItems)
    {
        GeoTelemetryData geoTelemetryData = JsonConvert.DeserializeObject<GeoTelemetryData>(truckFahrerGeoData.TelemetryData);

        if (geoTelemetryData == null)
        {
            return BadRequest($"geoTelemetryData null for id: {truckFahrerGeoData.Id}");
        }
        TruckFahrerGeoDataViewModel truckFahrerGeoDataViewModel = new TruckFahrerGeoDataViewModel
        {
            Speed = geoTelemetryData.Speed,
            Accuracy = geoTelemetryData.Accuracy,
            TruckAppId = geoTelemetryData.Activity.TruckAppId,
            TruckAuftragStatusId = geoTelemetryData.Activity.TruckAuftragStatusId,
            ClId = geoTelemetryData.Activity.ClId,
            TruckAuftragLaufStatusId = geoTelemetryData.Activity.TruckAuftragLaufStatusId,
            TaskId = geoTelemetryData.Activity.TaskId,
            TruckAuftragWorkflowStatusId = geoTelemetryData.Activity.TruckAuftragWorkflowStatusId
        };

        truckFahrerGeoDataItems.Add(truckFahrerGeoDataViewModel);
    }


    return Ok(truckFahrerGeoDataItems);
}
1
Erich Brunner

Ich hatte das gleiche Problem und nach einigen Recherchen fand ich heraus, dass ich mit HttpClient meine API aufrufen und die Antwort leicht lesen konnte. HttpClient gibt keinen Fehler aus, wenn die HTTP-Antwort einen Fehlercode enthält, setzt jedoch die IsSuccessStatusCode-Eigenschaft auf false.

Das ist meine Funktion mit dem HttpClient. Ich rufe das von meinem Controller aus an.

  public static async Task<HttpResponseMessage> HttpClientPost(string header, string postdata, string url)
        {
            string uri = apiUrl + url;
            using (var client = new HttpClient())
            {
                //client.BaseAddress = new Uri(uri);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", header);
                HttpResponseMessage response = await client.PostAsync(uri, new StringContent(postdata));

                return response;
            }
        }

Dies ist mein Controller-Code, in dem ich die Funktion aufrufe, die Antwort lese und feststelle, ob ich einen Fehler habe oder nicht, und entsprechend antworte. Beachten Sie, dass ich den IsSuccessStatusCode überprüfe.

                HttpResponseMessage response;
                string url = $"Setup/AddDonor";
                var postdata = JsonConvert.SerializeObject(donor);

                response = await ApiHandler.HttpClientPost(HttpContext.Session.GetString(tokenName), postdata, url);
                //var headers = response.Headers.Concat(response.Content.Headers);
                var responseBody = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    tnxresult = JsonConvert.DeserializeObject<TnxResult>(AppFunctions.CleanResponse(responseBody));

                    return Json(new
                    {
                        ok = true,
                        message = tnxresult.Message,
                        statusCode = tnxresult.StatusCode
                    });
                }
                else
                {
                  ApiError rs = JsonConvert.DeserializeObject<ApiError>(AppFunctions.CleanResponse(responseBody));

                    return Json(new
                    {
                        ok = false,
                        message = rs.Message,
                        statusCode = rs.StatusCode
                    });

                }

Meine API gibt Fehlermeldungen in JSON zurück. Wenn der Aufruf erfolgreich ist, packe ich die Antwort auch in JSON.

Die entscheidende Codezeile ist diese ...

var responseBody = await response.Content.ReadAsStringAsync();

Der HTTP-Inhalt wird als asynchrone Operation in eine Zeichenfolge serialisiert.

Danach kann ich meine JSON-Zeichenfolge in ein Objekt konvertieren und auf die Fehler-/Erfolgsmeldung und den Statuscode zugreifen.

0
Onsongo Moseti