Подтвердить что ты не робот

Создание новых методов результата действия IHttpActionResult

Можно ли использовать новый интерфейс IHttpActionResult для возврата ответного сообщения HttpStatusCode.NoContent?

В настоящее время я использую return new HttpResponseMessage( HttpStatusCode.NoContent ); и хотел бы преобразовать это в return NoContent();.

IHttpActionResult уже получил Ok(), Conflict() и NotFound(), но я не могу найти никаких для Forbidden() и NoContent(), которые мне нужно использовать в моем проекте.

Насколько легко добавлять другие типы результатов?

4b9b3361

Ответ 1

Я нашел этот примерный сайт, в котором показано, как добавить пользовательский метод IHttpActionResult, и я использовал его для создания методов Forbidden() и NoContent() с большим успехом.

public abstract class CommonApiController : ApiController
{
    public class ForbiddenResult : IHttpActionResult
    {
        private readonly HttpRequestMessage _request;
        private readonly string _reason;

        public ForbiddenResult(HttpRequestMessage request,string reason)
        {
            _request = request;
            _reason = reason;
        }

        public ForbiddenResult(HttpRequestMessage request)
        {
            _request = request;
            _reason = "Forbidden";
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            var response = _request.CreateResponse(HttpStatusCode.Forbidden,_reason);
            return Task.FromResult(response);
        }
    }

    public class NoContentResult : IHttpActionResult
    {
        private readonly HttpRequestMessage _request;
        private readonly string _reason;

        public NoContentResult(HttpRequestMessage request,string reason)
        {
            _request = request;
            _reason = reason;
        }

        public NoContentResult(HttpRequestMessage request)
        {
            _request = request;
            _reason = "No Content";
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            var response = _request.CreateResponse(HttpStatusCode.NoContent,_reason);
            return Task.FromResult(response);
        }
    }
}

И тогда я могу использовать его вот так:

public class InvoiceController : CommonApiController
{
    public async Task<IHttpActionResult> Post([FromBody]Invoice invoice)
    {
        if(User.IsInRole("Readonly"))
        {
            return Forbidden();
        }

        // Rest of code

    }
}

Ответ 2

Нет метода удобства для результата no-content, потому что по умолчанию, когда действие возвращает void, ответ будет иметь статус HTTP 204.

Если вы хотите явно указать, что в действии вы также можете вернуть StatusCode(HttpStatusCode.NoContent) из своего действия или

ResponseMessage(new HttpResponseMessage(HttpStatusCode.NoContent)).

Метод Unauthorized() дает вам статус 401, поэтому для Forbidden (403) вам также нужно будет использовать StatusCode(HttpStatusCode.Forbidden) или

ResponseMessage(new HttpResponseMessage(HttpStatusCode.Forbidden))

Ответ 3

Я попробовал реализацию @Intrepid и столкнулся с некоторыми проблемами. Я вижу два решения здесь:

Решение 1: Часть: return Forbidden(); не должно работать.

Компилятор не распознает это.

Вместо этого должно быть: return new ForbiddenResult(Request, "my reason");

ОБНОВЛЕНИЕ 1

Решение 2:

Я думаю, что именно это @Interpid намеревался в своей реализации, но он упустил несколько вещей.

Для использования return Forbidden(); CommonApiController должен быть обновлен функциями, которые возвращают пользовательский IHttpActionResult для Forbidden и NoContent

Класс должен выглядеть так:

public abstract class CommonApiController: ApiController {

    protected ForbiddenResult Forbidden() {
     return new ForbiddenResult(this.Request);
    }

    protected ForbiddenResult Forbidden(string reason) {
     return new ForbiddenResult(this.Request, reason);
    }

    protected NoContentResult NoContent() {
     return new NoContentResult(this.Request);
    }

    public class ForbiddenResult: IHttpActionResult {
     private readonly HttpRequestMessage _request;
     private readonly string _reason;

     public ForbiddenResult(HttpRequestMessage request, string reason) {
      _request = request;
      _reason = reason;
     }

     public ForbiddenResult(HttpRequestMessage request) {
      _request = request;
      _reason = "Forbidden";
     }

     public Task < HttpResponseMessage > ExecuteAsync(CancellationToken cancellationToken) {
      var response = _request.CreateResponse(HttpStatusCode.Forbidden, _reason);
      return Task.FromResult(response);
     }
    }

    public class NoContentResult: IHttpActionResult {
     private readonly HttpRequestMessage _request;
     private readonly string _reason;

     public NoContentResult(HttpRequestMessage request, string reason) {
      _request = request;
      _reason = reason;
     }

     public NoContentResult(HttpRequestMessage request) {
      _request = request;
      _reason = "No Content";
     }

     public Task < HttpResponseMessage > ExecuteAsync(CancellationToken cancellationToken) {
      var response = _request.CreateResponse(HttpStatusCode.NoContent, _reason);
      return Task.FromResult(response);
     }
    }
   }

В любом случае, если я ошибаюсь и ответ @Interpid правильный. Что мне здесь не хватает, чтобы заставить его реализацию работать?

Ответ 4

Если вы хотите включить фразу причины с ответом, не добавляя подкласс к ApiController, создайте объект ResponseMessage и верните его из действия методом ResponseMessage(). Попробуйте следующее:

public class InvoiceController : ApiController
{
    public async Task<IHttpActionResult> Post([FromBody]Invoice invoice)
    {
        if(User.IsInRole("Readonly"))
        {
            var response = new HttpResponseMessage(HttpStatusCode.Forbidden);

            response.ReasonPhrase = "User has the Readonly role";
            return ResponseMessage(response);
        }

        // Rest of code

    }
}

Ответ 5

Теперь вы можете использовать следующее (.Net Standard):

return StatusCode(HttpStatusCode.NoContent);

или (.Net Core 2. 1+)

return NoContent();

Ответ 6

Это хорошо сработало для меня:

public class CodeAndReason : IHttpActionResult
{
    private readonly HttpStatusCode code;
    private readonly string reason;

    public CodeAndReason(HttpStatusCode code, string reason)
    {
        this.code = code;
        this.reason = reason;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(code)
        {
            ReasonPhrase = reason,
            Content = new StringContent(reason),
        };

        return Task.FromResult(response);
    }

    public static IHttpActionResult NotFound(string reason)
    {
        return new CodeAndReason(HttpStatusCode.NotFound, reason);
    }

    public static IHttpActionResult Conflict(string reason)
    {
        return new CodeAndReason(HttpStatusCode.Conflict, reason);
    }

    public static IHttpActionResult Unauthorized(string reason)
    {
        return new CodeAndReason(HttpStatusCode.Unauthorized, reason);
    }
}

Используется в качестве:

return CodeAndReason.NotFound("Record {blah} not found");