Zwróć treść za pomocą IHttpActionResult, aby uzyskać niepoprawną odpowiedź

185

W przypadku zwrotu z kontrolera Web API 2 mogę zwrócić treść z odpowiedzią, jeśli odpowiedź jest OK (status 200) w następujący sposób:

    public IHttpActionResult Get()
    {
        string myResult = ...
        return Ok(myResult);
    }

Jeśli to możliwe, chcę tutaj użyć wbudowanych typów wyników: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

Moje pytanie brzmi: w przypadku innego rodzaju odpowiedzi (nie 200), jak mogę zwrócić z nią wiadomość (ciąg znaków)? Na przykład mogę to zrobić:

    public IHttpActionResult Get()
    {
       return InternalServerError();
    }

ale nie to:

    public IHttpActionResult Get()
    {
       return InternalServerError("Message describing the error here");
    }

Idealnie byłoby, gdyby uogólniono to, aby móc odesłać wiadomość z dowolną implementacją IHttpActionResult.

Czy muszę to zrobić (i zbudować własny komunikat odpowiedzi):

    public IHttpActionResult Get()
    {
       HttpResponseMessage responseMessage = ...
       return ResponseMessage(responseMessage);
    }

Czy jest jakiś lepszy sposób?

mayabelle
źródło
nie możesz użyć ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Ric
@ Milen, dziękuję. Coś takiego może działać. Nie podoba mi się to, że wymaga utworzenia innej implementacji IHttpActionResult dla każdej istniejącej implementacji, z której chcę móc korzystać.
mayabelle
@Ric, nie, parametr jest wyjątkiem. Chcę ustawić wiadomość jako ciąg. Nie rozwiązuje to również bardziej ogólnego przypadku, w którym kod niekoniecznie musi oznaczać wewnętrzny błąd serwera.
mayabelle
3
@mayabelle: Czy widziałeś odpowiedź Shamila Jakupowa? Przyjmowana odpowiedź jest znacznie prostsza i zwięzła.
Izaak

Odpowiedzi:

420

Możesz użyć tego:

return Content(HttpStatusCode.BadRequest, "Any object");
Shamil Yakupov
źródło
1
Krótkie i proste rozwiązanie. Posiadanie większej liczby kodów oznacza więcej błędów i czasochłonną konserwację.
Thomas.Benz
6
Kiedy próbuję tego, zwrócona wartość code(gdzie kod jest łańcuchem) return Content(HttpStatusCode.OK, code)jest zawarta w „co jest nieoczekiwane, czy jest jakiś powód tego? Np. "\"value\""Zwracana wartość to : używam mvc5
Deza
2
Jeśli musisz to zrobić spoza klasy ApiController, możesz użyć: zwróć nowy NegotiationContentResult <T> (kod, nowy T (...), kontroler)
Etherman
czy mogę zwrócić go z biblioteki klas? Do czego muszę się odwoływać?
Zestaw narzędzi
54

Możesz użyć HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpprzestrzeń nazw) w następujący sposób:

public IHttpActionResult Get()
{
   return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Message describing the error here"));
}

Preferowane jest tworzenie odpowiedzi na podstawie żądania, aby skorzystać z negocjacji treści interfejsu API sieci Web.

użytkownik1620220
źródło
6
Request.CreateErrorResponse zwraca HttpResponseMessage, a nie IHttpActionResult. Opisujesz dobrą praktykę tworzenia HttpResponseMessage, ale nie odpowiada na moje pytanie. W każdym razie dzięki!
mayabelle
@mayabelle możesz stworzyć beton IHttpActionResult i zawinąć kod w następujący sposób:
Quoc Nguyen
1
To zadziałało dla mnie, ale użyłem Request.CreateResponse, dzięki czemu błąd pojawia się jako ciąg zamiast w kluczu wiadomości.
Chemik
Pojawia się błąd, fragment kodu nie działa. Mówi, że „żądanie” jest zerowe. Próbuję użyć Request.CreateResponse @ user1620220
Sheena Agrawal
@SheenaAgrawal Ten kod można wykonać tylko w kontekście żądania HTTP. Jeśli ApiController.Requestjest pusty, oznacza to, że nie masz odpowiedniego kontekstu lub coś jest nie tak z architekturą WebAPI.
user1620220
35

Skończyło się na następującym rozwiązaniu:

public class HttpActionResult : IHttpActionResult
{
    private readonly string _message;
    private readonly HttpStatusCode _statusCode;

    public HttpActionResult(HttpStatusCode statusCode, string message)
    {
        _statusCode = statusCode;
        _message = message;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = new HttpResponseMessage(_statusCode)
        {
            Content = new StringContent(_message)
        };
        return Task.FromResult(response);
    }
}

... które można wykorzystać w następujący sposób:

public IHttpActionResult Get()
{
   return new HttpActionResult(HttpStatusCode.InternalServerError, "error message"); // can use any HTTP status code
}

Jestem otwarty na propozycje ulepszeń. :)

mayabelle
źródło
1
Odpowiedź Shamila Jakupowa jest najlepszą odpowiedzią, ale tylko z wnętrza klasy ApiController - musi zostać przepisana jako coś w rodzaju „zwróć nowy NegotiationContentResult <T> (kod, nowy T (...), kontroler)” do użycia spoza klasa kontrolera. W takim przypadku rozwiązanie takie jak to powyżej może być bardziej czytelne.
Etherman
16

Możesz także:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));
ilans
źródło
1
Tak, ale
trudno
7

Każdy, kto jest zainteresowany zwrotem czegokolwiek z dowolnym kodem statusu ze zwrotem ResponseMessage:

//CreateResponse(HttpStatusCode, T value)
return ResponseMessage(Request.CreateResponse(HttpStatusCode.XX, object));
CularBytes
źródło
7

W ASP.NET Web API 2 możesz zawinąć dowolne ResponseMessagew ResponseMessageResult :

public IHttpActionResult Get()
{
   HttpResponseMessage responseMessage = ...
   return new ResponseMessageResult(responseMessage);
}

W niektórych przypadkach może to być najprostszy sposób na uzyskanie pożądanego rezultatu, chociaż generalnie może być preferowane użycie różnych wyników w System.Web.Http.Results .

sfuqua
źródło
6

Prosty:

return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Your message"));

Pamiętaj, aby odwoływać się do System.Net.Http i System.Net .

Rodrigo Reis
źródło
2

Polecam przeczytać ten post. Istnieje wiele sposobów korzystania z istniejącego HttpResponse zgodnie z sugestią, ale jeśli chcesz skorzystać z Web Api 2, spójrz na użycie niektórych z wbudowanych opcji IHttpActionResult, takich jak

return Ok() 

lub

return NotFound()

Wybierz odpowiedni typ zwrotu dla kontrolerów interfejsu API sieci Web

wegunterjr
źródło
2

Bardziej szczegółowy przykład z obsługą kodu HTTP nie zdefiniowanego w języku C # HttpStatusCode.

public class MyController : ApiController
{
    public IHttpActionResult Get()
    {
        HttpStatusCode codeNotDefined = (HttpStatusCode)429;
        return Content(codeNotDefined, "message to be sent in response body");
    }
}

Contentjest wirtualną metodą zdefiniowaną w klasie abstrakcyjnej ApiController, stanowiącej podstawę kontrolera. Zobacz deklarację jak poniżej:

protected internal virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value);
temat
źródło
1

@mayabelle możesz stworzyć beton IHttpActionResult i zawinąć kod w następujący sposób:

public class NotFoundPlainTextActionResult : IHttpActionResult
{
    public NotFoundPlainTextActionResult(HttpRequestMessage request, string message)
    {
        Request = request;
        Message = message;
    }

    public string Message { get; private set; }
    public HttpRequestMessage Request { get; private set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(ExecuteResult());
    }

    public HttpResponseMessage ExecuteResult()
    {
        var response = new HttpResponseMessage();

        if (!string.IsNullOrWhiteSpace(Message))
            //response.Content = new StringContent(Message);
            response = Request.CreateErrorResponse(HttpStatusCode.NotFound, new Exception(Message));

        response.RequestMessage = Request;
        return response;
    }
}
Quoc Nguyen
źródło
0

Miałem ten sam problem. Chcę utworzyć niestandardowy wynik dla moich kontrolerów interfejsu API, aby wywoływać je w podobny sposób return Ok("some text");

Następnie zrobiłem to: 1) Utwórz niestandardowy typ wyniku za pomocą singletone

public sealed class EmptyResult : IHttpActionResult
{
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.NoContent) { Content = new StringContent("Empty result") });
    }
}

2) Utwórz niestandardowy kontroler za pomocą nowej metody:

public class CustomApiController : ApiController
{
    public IHttpActionResult EmptyResult()
    {
        return new EmptyResult();
    }
}

A potem mogę wywoływać je w moich kontrolerach w następujący sposób:

public IHttpActionResult SomeMethod()
    {
       return EmptyResult();
    }
Merchezatter
źródło
0

ta odpowiedź oparta jest na odpowiedzi Shamila Jakupowa, z prawdziwym przedmiotem zamiast łańcucha.

using System.Dynamic;

dynamic response = new ExpandoObject();
response.message = "Email address already exist";

return Content<object>(HttpStatusCode.BadRequest, response);
Kugan Kumar
źródło
1
Treść <T> jest bardzo przydatna
LastTribunal
0

Z wyjątkami zwykle tak robię

 catch (Exception ex)
        {
            return InternalServerError(new ApplicationException("Something went wrong in this request. internal exception: " + ex.Message));
        }
Ahsant
źródło
0

Powyższe rzeczy są naprawdę pomocne.

Podczas tworzenia usług internetowych, jeśli weźmiesz pod uwagę usługi, konsument będzie bardzo wdzięczny. Starałem się zachować jednolitość wyjścia. Możesz także podać uwagę lub komunikat o błędzie. Konsument usługi internetowej może tylko sprawdzić, czy IsSuccess ma wartość true, czy nie, aby upewnić się, że wystąpił problem i postępować zgodnie z sytuacją.

  public class Response
    {
        /// <summary>
        /// Gets or sets a value indicating whether this instance is success.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is success; otherwise, <c>false</c>.
        /// </value>
        public bool IsSuccess { get; set; } = false;

        /// <summary>
        /// Actual response if succeed 
        /// </summary>
        /// <value>
        /// Actual response if succeed 
        /// </value>
        public object Data { get; set; } = null;

        /// <summary>
        /// Remark if anythig to convey
        /// </summary>
        /// <value>
        /// Remark if anythig to convey
        /// </value>
        public string Remark { get; set; } = string.Empty;
        /// <summary>
        /// Gets or sets the error message.
        /// </summary>
        /// <value>
        /// The error message.
        /// </value>
        public object ErrorMessage { get; set; } = null;


    }  




[HttpGet]
        public IHttpActionResult Employees()
        {
            Response _res = new Response();
            try
            { 
                DalTest objDal = new DalTest(); 
                _res.Data = objDal.GetTestData();
                _res.IsSuccess = true;
                return Ok<Response>(_res);
            }
            catch (Exception ex)
            {
                _res.IsSuccess = false;
                _res.ErrorMessage = ex;
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, _res )); 
            } 
        }

Jeśli masz jakieś sugestie, możesz podać sugestie :)

Amol Khandagale
źródło
-1

Przepraszam za późną odpowiedź, dlaczego nie skorzystasz z niej w prosty sposób

return BadRequest("your message");

Używam tego do wszystkiego IHttpActionResult błędów, działa dobrze

tutaj jest dokumentacja: https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx

benraay
źródło
7
Ponieważ nie wszystkie błędy są wynikiem złych żądań, więc 400odpowiedź byłaby niewłaściwa. OP konkretnie podał 500odpowiedź jako przykład.
user1620220,
Tak, jest to możliwe tylko z BadRequest, inne typy nie biorą argumentu wiadomości
benraay