Возврат содержимого с помощью IHttpActionResult для ответа не OK

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

или есть лучший способ?

mayabelle
источник
как насчет этого: stackoverflow.com/questions/10732644/…
Милен
не могли бы вы использовать ApiController.InternalServerError msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx
Рик,
@ Милен, спасибо. Нечто подобное может сработать. Часть, которая мне не нравится, это то, что она требует создания отдельной реализации 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, вы можете использовать: return new NegotiatedContentResult <T> (код, новый T (...), контроллер)
Etherman
Могу ли я вернуть его из библиотеки классов? Что мне нужно для ссылки?
Инструментарий
54

Вы можете использовать HttpRequestMessagesExtensions.CreateErrorResponse ( System.Net.Httpnamespace), например так:

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

Предпочтительно создавать ответы на основе запроса, чтобы воспользоваться преимуществами согласования содержимого Web API.

user1620220
источник
6
Request.CreateErrorResponse возвращает HttpResponseMessage, а не IHttpActionResult. То, что вы описываете, является хорошей практикой для создания HttpResponseMessage, но не отвечает на мой вопрос. Спасибо, в любом случае!
Mayabelle
@mayabelle, вы можете создать бетон IHttpActionResult и обернуть этот код следующим образом:
Quoc Nguyen
1
Это сработало для меня, но я использовал Request.CreateResponse, чтобы ошибка отображалась в виде строки, а не под ключом сообщения.
Химик
Я получаю сообщение об ошибке, фрагмент не работает. Он говорит, что «запрос» является нулевым. Я пытаюсь использовать Request.CreateResponse @ user1620220
Шина Агравал
@SheenaAgrawal Этот код может быть выполнен только в контексте HTTP-запроса. Если ApiController.Requestноль, это означает, что вы находитесь не в правильном контексте, или что-то не работает в вашей архитектуре WebAPI.
user1620220
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
}

Я открыт для предложений по улучшению. :)

mayabelle
источник
1
Ответ Шамиля Якупова - лучший ответ, но только изнутри класса ApiController - его нужно переписать как что-то вроде «return new NegotiatedContentResult <T> (code, new T (...), controller)» для использования извне Контроллер класса. В этом случае решение, подобное приведенному выше, может быть более читабельным.
Etherman
16

Вы также можете сделать:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));
ilans
источник
1
Да, но возвращать текст этого сообщения
боль
7

Любой, кто заинтересован в возвращении чего-либо с любым кодом состояния с возвратом ResponseMessage:

//CreateResponse(HttpStatusCode, T value)
return ResponseMessage(Request.CreateResponse(HttpStatusCode.XX, object));
CularBytes
источник
7

В ASP.NET Web API 2 вы можете заключить любое ResponseMessageв ResponseMessageResult :

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

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

sfuqua
источник
6

Просто:

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

Не забудьте сослаться на System.Net.Http и System.Net .

Родриго Рейс
источник
2

Я бы порекомендовал прочитать этот пост. Существует множество способов использовать существующий HttpResponse, как это предлагается, но если вы хотите использовать преимущества Web Api 2, обратите внимание на использование некоторых встроенных параметров IHttpActionResult, таких как

return Ok() 

или

return NotFound()

Выберите правильный тип возврата для контроллеров Web Api

wegunterjr
источник
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);
themefield
источник
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();
    }
Merchezatter
источник
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));
        }
ahsant
источник
0

Выше вещи действительно полезны.

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

  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

benraay
источник
7
Поскольку не все ошибки являются результатом неправильных запросов, 400ответ будет неуместным. ОП конкретно дал 500ответ в качестве примера.
user1620220
Да, это возможно только с BadRequest, другие типы не принимают аргумент сообщения
benraay