Me voy a volver un NotFound IHttpActionResult, cuando algo no se encuentra en mi WebApi CONSEGUIR la acción. Junto con esta respuesta, quiero enviar un mensaje personalizado y/o el mensaje de excepción (si los hubiere). El actual ApiController‘s NotFound() método no proporciona una sobrecarga para pasar un mensaje.

¿Hay alguna manera de hacerlo? o voy a tener que escribir mi propio personalizado IHttpActionResult?

  • ¿Quieres volver el mismo mensaje para todos No se Encontraron resultados?
  • No, podría ser un mensaje diferente dependiendo de la situación.
InformationsquelleAutor Ajay Jadhav | 2013-11-22

9 Comentarios

  1. 81

    Tendría que escribir su propio resultado de una acción si desea personalizar el mensaje de respuesta de la forma.

    Hemos querido ofrecer la respuesta más común mensaje de formas fuera de la caja para cosas como simple vacío 404, pero también queríamos mantener estos resultados tan simple como sea posible; una de las principales ventajas de la utilización de resultados de la acción es la que hace que su método de acción mucho más fáciles de la prueba de unidad. El más propiedades de las que nos ponemos resultados de la acción, la más cosas de su unidad de prueba de necesidades a tener en cuenta para asegurarse de que el método de acción es haciendo lo que se esperaría.

    A menudo me quieren disponer de la capacidad para proporcionar un mensaje personalizado, así que siéntase libre de registro de un error para nosotros a considerar el apoyo que el resultado de una acción en un futuro de liberación:
    https://aspnetwebstack.codeplex.com/workitem/list/advanced

    Una cosa buena acerca de los resultados de la acción, sin embargo, es que siempre puedes escribir tus propios bastante fácil si se quiere hacer algo ligeramente diferente. He aquí cómo usted puede hacer en su caso (si desea que el mensaje de error en text/plain; si desea JSON, te gustaría hacer algo diferente con el contenido):

    public class NotFoundTextPlainActionResult : IHttpActionResult
    {
        public NotFoundTextPlainActionResult(string message, HttpRequestMessage request)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
    
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
    
            Message = message;
            Request = request;
        }
    
        public string Message { get; private set; }
    
        public HttpRequestMessage Request { get; private set; }
    
        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute());
        }
    
        public HttpResponseMessage Execute()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound);
            response.Content = new StringContent(Message); //Put the message in the response body (text/plain content).
            response.RequestMessage = Request;
            return response;
        }
    }
    
    public static class ApiControllerExtensions
    {
        public static NotFoundTextPlainActionResult NotFound(this ApiController controller, string message)
        {
            return new NotFoundTextPlainActionResult(message, controller.Request);
        }
    }

    Luego, en su método de acción, usted puede hacer algo como esto:

    public class TestController : ApiController
    {
        public IHttpActionResult Get()
        {
            return this.NotFound("These are not the droids you're looking for.");
        }
    }

    Si usted utiliza un personalizadas del controlador de la clase base (en lugar de directamente la herencia de ApiController), también se podría eliminar el «esto». parte (que es, por desgracia necesario cuando se llama a un método de extensión):

    public class CustomApiController : ApiController
    {
        protected NotFoundTextPlainActionResult NotFound(string message)
        {
            return new NotFoundTextPlainActionResult(message, Request);
        }
    }
    
    public class TestController : CustomApiController
    {
        public IHttpActionResult Get()
        {
            return NotFound("These are not the droids you're looking for.");
        }
    }
    • Escribí exactamente similar implementación de ‘IHttpActionResult’, pero no específica para ‘NotFound» resultado. Esto probablemente va a funcionar para Todos «HttpStatusCodes’. Mi CustomActionResult código es algo así como este Y mi controler del ‘Get()’ acción se parece a esto: ‘público IHttpActionResult Get() { return CustomNotFoundResult(«Meessage para Volver.»); }’ También, en que se registra un bug en CodePlex para tener en cuenta esto en el futuro de liberación.
    • Yo uso ODataControllers y tuve que usar esto.NotFound(«bla»);
    • Muy buen post, pero me gustaría recomendar en contra de la herencia de la punta. Mi equipo decidió hacer exactamente eso hace mucho tiempo, y es hinchado las clases mucho por hacerlo. Me acabo de refactorizar todo en los métodos de extensión y se alejó de la cadena de herencia. Me gustaría en serio recomiendo a la gente a considerar cuidadosamente cuando se debe utilizar la herencia como este. Generalmente, la composición es mucho mejor, porque es mucho más disociadas.
    • Esta funcionalidad debería haber estado fuera-de-la-caja. Incluyendo un opcional «ResponseBody» parámetro no debe afectar a la unidad de pruebas.
  2. 207

    Aquí un one-liner para el retorno de un IHttpActionResult NotFound con un simple mensaje:

    return Content(HttpStatusCode.NotFound, "Foo does not exist.");
    • La gente debería votar a esta respuesta. Es agradable y fácil!
    • Ser consciente de que esta solución no establece el encabezado HTTP en estado de «404 No Encontrado».
    • El código de estado http desde el servidor 404, ¿necesitas algo más?
    • Estás en lo correcto. Yo estaba usando el Controlador.Contenido(…). Debería haber usado el ApiController.Contenido(…) – Mi mal.
    • Gracias compañero, esto era exactamente lo que estaba buscando
    • Esta respuesta debe tener más votos, el objeto pasa es todavía la serie. Funciona como un encanto.

  3. 28

    Usted podría utilizar ResponseMessageResult si te gusta:

    var myCustomMessage = "your custom message which would be sent as a content-negotiated response"; 
    return ResponseMessage(
        Request.CreateResponse(
            HttpStatusCode.NotFound, 
            myCustomMessage
        )
    );

    sí, si usted necesita mucho más corto versiones, entonces supongo que necesita para implementar su costumbre resultado de una acción.

    • Me fui con este método, ya que parecía limpio. Me acaba de definir el mensaje personalizado en otros lugares y con sangría de código de retorno.
    • Me gusta esta mejor que el Contenido, ya que en realidad devuelve un objeto que puede analizar con un Mensaje de propiedad como el estándar BadRequest método.
  4. 7

    Puede utilizar ReasonPhrase propiedad de HttpResponseMessage clase

    catch (Exception exception)
    {
      throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)
      {
        ReasonPhrase = exception.Message
      });
    }
    • Gracias. Bueno.. esto debería funcionar, pero entonces voy a tener que construir la HttpResponseException en mi propio en cada acción. Para mantener el código menos, yo estaba pensando si podría utilizar cualquier WebApi 2 características (como el ready-made NotFount(), Aceptar() métodos) y pasar el ReasonPhrase mensaje.
    • Usted puede crear su propio método de extensión NotFound(con la Excepción de la excepción), que lanzará correcta HttpResponseException
    • resultados de la acción se introdujeron para mejorar la capacidad de prueba. Lanzando HttpResponseException aquí sería comprometer. También aquí no tenemos ninguna excepción, pero el OP está buscando para enviar un mensaje de vuelta.
    • Ok, si no quieres usar NUint para la prueba, usted puede escribir su propia implementación de NotFoundResult y reescribir su ExecuteAsync para devolver el mensaje de datos. Y volver instancia de esta clase, como resultado de su acción invocación.
    • Tenga en cuenta que ahora se puede pasar el código de estado directamente, por ejemplo, HttpResponseException(HttpStatusCode.NotFound)
    • No funcionará si la excepción.Mensaje contiene por ejemplo un salto de línea.

  5. 2

    Lo resuelto por simplemente derivados de OkNegotiatedContentResult y reemplazar el código HTTP de la respuesta resultante mensaje. Esta clase permite devolver el contenido del cuerpo con cualquier código de respuesta HTTP.

    public class CustomNegotiatedContentResult<T> : OkNegotiatedContentResult<T>
    {
        public HttpStatusCode HttpStatusCode;
    
        public CustomNegotiatedContentResult(
            HttpStatusCode httpStatusCode, T content, ApiController controller)
            : base(content, controller)
        {
            HttpStatusCode = httpStatusCode;
        }
    
        public override Task<HttpResponseMessage> ExecuteAsync(
            CancellationToken cancellationToken)
        {
            return base.ExecuteAsync(cancellationToken).ContinueWith(
                task => { 
                    //override OK HTTP status code with our own
                    task.Result.StatusCode = HttpStatusCode;
                    return task.Result;
                },
                cancellationToken);
        }
    }
  6. 2

    Usted puede crear una costumbre negociado de contenido como resultado d3m3t3er sugerido. Sin embargo, yo iba a heredar. También, si usted necesita sólo para regresar NotFound, no es necesario inicializar el estado http de constructor.

    public class NotFoundNegotiatedContentResult<T> : NegotiatedContentResult<T>
    {
        public NotFoundNegotiatedContentResult(T content, ApiController controller)
            : base(HttpStatusCode.NotFound, content, controller)
        {
        }
    
        public override Task<HttpResponseMessage> ExecuteAsync(
            CancellationToken cancellationToken)
        {
            return base.ExecuteAsync(cancellationToken).ContinueWith(
                task => task.Result, cancellationToken);
        }
    }
  7. 1

    Si se hereda de la base NegotitatedContentResult<T>, como se ha mencionado, y que no se necesita para transformar su content (por ejemplo, sólo desea devolver un string), entonces usted no necesita reemplazar el ExecuteAsync método.

    Todo lo que necesita hacer es proporcionar una adecuada definición de tipo y un constructor que le dice a la base de Código de Estado HTTP para volver. Todo lo demás funciona.

    Aquí son ejemplos para ambas NotFound y InternalServerError:

    public class NotFoundNegotiatedContentResult : NegotiatedContentResult<string>
    {
        public NotFoundNegotiatedContentResult(string content, ApiController controller)
            : base(HttpStatusCode.NotFound, content, controller) { }
    }
    
    public class InternalServerErrorNegotiatedContentResult : NegotiatedContentResult<string>
    {
        public InternalServerErrorNegotiatedContentResult(string content, ApiController controller)
            : base(HttpStatusCode.InternalServerError, content, controller) { }
    }

    Y, a continuación, usted puede crear los correspondientes métodos de extensión para ApiController (o hacerlo en una clase base (si tiene uno):

    public static NotFoundNegotiatedContentResult NotFound(this ApiController controller, string message)
    {
        return new NotFoundNegotiatedContentResult(message, controller);
    }
    
    public static InternalServerErrorNegotiatedContentResult InternalServerError(this ApiController controller, string message)
    {
        return new InternalServerErrorNegotiatedContentResult(message, controller);
    }

    Y, a continuación, funcionan exactamente igual que los métodos integrados. Usted puede llamar a la existente NotFound() o usted puede llamar a su nueva costumbre de NotFound(myErrorMessage).

    Y, por supuesto, usted puede deshacerse de los «hard-coded» los tipos de cadena, en las definiciones de tipos personalizados y dejar genérico si quieres, pero entonces usted puede tiene que preocuparse acerca de la ExecuteAsync cosas, dependiendo de lo que su <T> en realidad es.

    Usted puede buscar a través de la código fuente para NegotiatedContentResult<T> para ver todo lo que hace. No hay mucho a ella.

  8. 1

    Me fue la necesidad de crear un IHttpActionResult instancia en el cuerpo de un IExceptionHandler clase, con el fin de establecer el ExceptionHandlerContext.Result de la propiedad. Sin embargo, yo también quería establecer una costumbre ReasonPhrase.

    Me encontré con que un ResponseMessageResult podría ajustar un HttpResponseMessage (que permite ReasonPhrase a configurarse fácilmente).

    Por Ejemplo:

    public class MyExceptionHandler : ExceptionHandler
    {
        public override void Handle(ExceptionHandlerContext context)
        {
            var ex = context.Exception as IRecordNotFoundException;
            if (ex != null)
            {
                context.Result = new ResponseMessageResult(new HttpResponseMessage(HttpStatusCode.NotFound) { ReasonPhrase = $"{ex.EntityName} not found" });
            }
        }
    }
  9. 0

    Iknow PO preguntó con un mensaje de texto, pero otra opción solo para devolver un mensaje de error 404 es hacer que el método devuelva un IHttpActionResult y utilizar el código de estado de la función

        public async Task<IHttpActionResult> Get([FromUri]string id)
        {
           var item = await _service.GetItem(id);
           if(item == null)
           {
               StatusCode(HttpStatusCode.NotFound);
           }
           return Ok(item);
        }

Dejar respuesta

Please enter your comment!
Please enter your name here