Поверніть вміст за допомогою IHttpActionResult для невідповідної відповіді


185

Для повернення з контролера Web API 2 я можу повернути вміст з відповіддю, якщо відповідь ОК (стан 200) таким чином:

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

Якщо можливо, я хочу тут використовувати вбудовані типи результатів: https://msdn.microsoft.com/en-us/library/system.web.http.results(v=vs.118).aspx

Моє запитання полягає в тому, що для іншого типу відповіді (не 200), як я можу повернути повідомлення (рядок) разом з ним? Наприклад, я можу це зробити:

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

але не це:

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

В ідеалі я хочу, щоб це було узагальнено, щоб я міг надсилати повідомлення назад із будь-якою з реалізацій IHttpActionResult.

Чи потрібно це робити (і створити власне повідомлення відповіді):

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

чи є кращий спосіб?



ви не можете використовувати ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Рік

@Milen, дякую Щось подібне може спрацювати. Частина, яка мені не подобається, це вимагає створення іншої реалізації IHttpActionResult для кожної існуючої реалізації, яку я хочу мати змогу використовувати.
mayabelle

@ Ric, ні, параметр - виняток. Я хочу встановити повідомлення як рядок. Крім того, це не стосується більш загального випадку, коли код не обов'язково має бути внутрішньою помилкою сервера.
mayabelle

3
@mayabelle: Ви бачили відповідь Шаміля Якупова? Набагато простіше і стисліше, що прийнята відповідь.
Ісаак

Відповіді:


420

Ви можете скористатися цим:

return Content(HttpStatusCode.BadRequest, "Any object");

1
Коротке і просте рішення. Маючи більше кодів, це означає більше помилок і трудомістке обслуговування.
Thomas.Benz

6
Коли я намагаюсь це, повернене значення code(де код - це рядок) в return Content(HttpStatusCode.OK, code)інкапсульоване в "що несподівано, чи є причина для цього? Наприклад, значення, яке повертається, "\"value\""я використовую mvc5
Deza

2
Якщо вам потрібно зробити це поза класом ApiController, тоді ви можете використовувати: повернути новий NegotiatedContentResult <T> (код, новий T (...), контролер)
Etherman

чи можу я повернути його з бібліотеки класів? Що мені потрібно для посилання?
Інструментарій

54

Ви можете використовувати HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpпростір імен), наприклад:

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

Переважно створювати відповіді на основі запиту, щоб скористатися переговорами щодо вмісту Web API.


6
Request.CreateErrorResponse повертає HttpResponseMessage, а не IHttpActionResult. Те, що ви описуєте, є хорошою практикою створення HttpResponseMessage, але не відповідає моєму питанню. Все одно, дякую!
mayabelle

@mayabelle ви можете створити бетон IHttpActionResult і загорнув такий код так:
Quoc Nguyen

1
Це працювало для мене, але я використовував Request.CreateResponse, щоб помилка відображалася як рядок замість клавіші повідомлення.
Хімік

Я отримую помилку, фрагмент виходить з ладу. У ньому сказано, що "запит" є недійсним. Я намагаюся використовувати Request.CreateResponse @ user1620220
Sheena Agrawal

@SheenaAgrawal Цей код може бути виконаний лише в контексті HTTP-запиту. Якщо ApiController.Requestnull, це означає, що ви не в правильному контексті, або щось порушено у вашій архітектурі WebAPI.
користувач1620220

35

Я закінчився таким рішенням:

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);
    }
}

... які можна використовувати так:

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

Я відкритий для пропозицій щодо вдосконалення. :)


1
Відповідь Шаміля Якупова - найкраща відповідь, але тільки зсередини класу ApiController - її потрібно переписати як щось на кшталт "повернути новий договірний контентРезультат <T> (код, новий T (...), контролер)", який буде використовуватися ззовні клас контролера. У такому випадку таке рішення, як це вище, може бути більш читабельним.
Етерман

16

Ви також можете зробити:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));

1
Так, але боляче повернути текст цього повідомлення
користувачSteve

7

Усі, хто зацікавлений повернути що-небудь із будь-яким кодом статусу із поверненням ResponseMessage:

//CreateResponse(HttpStatusCode, T value)
return ResponseMessage(Request.CreateResponse(HttpStatusCode.XX, object));

7

У веб-API 2 ASP.NET ви можете обгорнути будь-яку інформацію ResponseMessageу ResponseMessageResult :

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

У деяких випадках це може бути найпростіший спосіб отримати бажаний результат, хоча, як правило, бажано використовувати різні результати в System.Web.Http.Results .


6

Простий:

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

Пам'ятайте про посилання System.Net.Http і System.Net .


2

Я рекомендую прочитати цю публікацію. Існує безліч способів використання існуючих HttpResponse, як пропонується, але якщо ви хочете скористатися Web Api 2, тоді перегляньте використання деяких вбудованих параметрів IHttpActionResult, таких як

return Ok() 

або

return NotFound()

Виберіть правильний тип повернення для веб-контролерів Api


2

Більш детальний приклад із підтримкою HTTP-коду, не визначеного в C # HttpStatusCode.

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

Contentце віртуальний метод, визначений в абстрактному класі ApiController, база контролера. Дивіться декларацію, як показано нижче:

protected internal virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value);

1

@mayabelle ви можете створити бетон IHttpActionResult і обернути такий код так:

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;
    }
}

0

У мене була така ж проблема. Я хочу створити власні результати для своїх контролерів api, щоб їх називати return Ok("some text");

Тоді я зробив це: 1) Створити власний тип результату з однотонним

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) Створіть спеціальний контролер за допомогою нового методу:

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

І тоді я можу викликати їх у своїх контролерах, наприклад:

public IHttpActionResult SomeMethod()
    {
       return EmptyResult();
    }

0

ця відповідь заснована на відповіді Шаміля Якупова, з реальним об'єктом замість рядка.

using System.Dynamic;

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

return Content<object>(HttpStatusCode.BadRequest, response);

1
Вміст <T> дуже корисний
LastTribunal

0

За виняток, як правило, роблю

 catch (Exception ex)
        {
            return InternalServerError(new ApplicationException("Something went wrong in this request. internal exception: " + ex.Message));
        }

0

Наведені речі справді корисні.

Під час створення веб-сервісів, якщо ви приймете справу з послугами, споживач буде дуже вдячний. Я намагався зберегти рівномірність виходу. Також ви можете надати зауваження або фактичне повідомлення про помилку. Споживач веб-сервісу може лише перевірити IsSuccess істинним чи ні інший буде впевнений, що існує проблема, і діяти відповідно до ситуації.

  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 )); 
            } 
        }

Ви можете дати пропозицію, якщо є :)


-1

Вибачте за пізню відповідь, чому ви не просто користуєтесь

return BadRequest("your message");

Я використовую його для всіх своїх IHttpActionResultпомилок, його добре працює

ось документація: https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx


7
Оскільки не всі помилки є результатом поганих запитів, тож 400відповідь була б недоречною. ОП спеціально дала 500відповідь як приклад.
користувач1620220

Так, це можливо лише з BadRequest, інші типи не беруть аргумент повідомлення
benraay
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.