218

For returning from a Web API 2 controller, I can return content with the response if the response is OK (status 200) like this:

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

If possible, I want to use the built-in result types here when possible

My question is, for another type of response (not 200), how can I return a message (string) with it? For example, I can do this:

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

but not this:

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

Ideally, I want this to be generalized so that I can send a message back with any of the implementations of IHttpActionResult.

Do I need to do this (and build my response message):

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

or is there a better way?

spaleet
  • 838
  • 2
  • 10
  • 23
mayabelle
  • 9,804
  • 9
  • 36
  • 59
  • how about this: http://stackoverflow.com/questions/10732644/best-practice-to-return-errors-in-asp-net-web-api – Milen Feb 18 '15 at 16:37
  • could you not use `ApiController.InternalServerError` https://msdn.microsoft.com/en-us/library/dn292630(v=vs.118).aspx – Ric Feb 18 '15 at 16:48
  • @Milen, Thank you. Something like that might work. The part I don't like is it requires creating a different IHttpActionResult implementation for each existing implementation I want to be able to use. – mayabelle Feb 18 '15 at 16:53
  • @Ric, no, the parameter is an Exception. I want to set a message as a string. Also, this doesn't address a more general case where the code might not necessarily be internal server error. – mayabelle Feb 18 '15 at 16:54
  • 3
    @mayabelle: Did you see Shamil Yakupov`s answer? It's much simpler and concise that the accepted answer. – Isaac Jun 18 '16 at 03:15

17 Answers17

472

You can use this:

return Content(HttpStatusCode.BadRequest, "Any object");
Shamil Yakupov
  • 5,409
  • 2
  • 16
  • 21
  • 1
    Short and simple solution. Having more codes means more bugs and time consuming maintenance. – Thomas.Benz Mar 08 '16 at 15:02
  • 8
    When im trying this, the returned value of `code` (where code is a string) in `return Content(HttpStatusCode.OK, code)` is encapsulated in " which is unexpected, is there any reason for this? eg the value which is returned is `"\"value\""` I'm using mvc5 – Deza Jun 23 '16 at 15:49
  • 2
    If you need to do this from outside the ApiController class then you can use: return new NegotiatedContentResult(code, new T(...), controller) – Etherman Aug 18 '17 at 10:59
  • can i return it from a class library? What do I need to reference? – Toolkit Aug 14 '18 at 07:35
  • the simplest answer is usually the best and most applicable one – I Stand With Russia Oct 20 '22 at 22:15
64

You can use HttpRequestMessagesExtensions.CreateErrorResponse (System.Net.Http namespace), like so:

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

It is preferable to create responses based on the request to take advantage of Web API's content negotiation.

user1620220
  • 1,295
  • 8
  • 15
  • 7
    Request.CreateErrorResponse returns an HttpResponseMessage, not IHttpActionResult. What you describe is good practice for creating an HttpResponseMessage but doesn't address my question. Thanks anyway! – mayabelle Feb 18 '15 at 16:54
  • @mayabelle you can create IHttpActionResult concrete and wrapped those code like this: – Quoc Nguyen Mar 03 '15 at 09:18
  • 1
    This worked for me but I used Request.CreateResponse so that the error shows as a string instead of under Message key. – Chemist Feb 08 '17 at 21:07
  • I am getting an error, the snippet is failing. It says 'request' is null. I am trying to use Request.CreateResponse @user1620220 – Sheena Agrawal Jan 08 '18 at 14:50
  • @SheenaAgrawal This code can only be executed in the context of an HTTP request. If `ApiController.Request` is null it means you are not in the right context, or something is broken in your WebAPI architecture. – user1620220 Jan 17 '18 at 16:12
44

I ended up going with the following solution:

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

... which can be used like this:

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

I'm open to suggestions for improvement. :)

mayabelle
  • 9,804
  • 9
  • 36
  • 59
  • 2
    Shamil Yakupov's answer is the best answer but only from inside the ApiController class - it needs to be rewritten as something like "return new NegotiatedContentResult(code, new T(...), controller)" to be used from outside the controller class. In that case a solution such as this one above may be more readable. – Etherman Aug 18 '17 at 11:07
18

You can also do:

return InternalServerError(new Exception("SOME CUSTOM MESSAGE"));
ilans
  • 2,537
  • 1
  • 28
  • 29
12

Simple:

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

Remember to reference System.Net.Http and System.Net.

Whit Waldo
  • 4,806
  • 4
  • 48
  • 70
Rodrigo Reis
  • 1,097
  • 12
  • 21
7

Anyone who is interested in returning anything with any statuscode with returning ResponseMessage:

//CreateResponse(HttpStatusCode, T value)
return ResponseMessage(Request.CreateResponse(HttpStatusCode.XX, object));
CularBytes
  • 9,924
  • 8
  • 76
  • 101
7

In ASP.NET Web API 2, you can wrap any ResponseMessage in a ResponseMessageResult:

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

In some cases this may be the simplest way to get the desired result, although generally it might be preferable to use the various results in System.Web.Http.Results.

sfuqua
  • 5,797
  • 1
  • 32
  • 33
6

I would recommend reading this post. There are tons of ways to use existing HttpResponse as suggested, but if you want to take advantage of Web Api 2, then look at using some of the built-in IHttpActionResult options such as

return Ok() 

or

return NotFound()

Choose the right return type for Web Api Controllers

wegunterjr
  • 141
  • 2
  • 9
4

A more detailed example with support of HTTP code not defined in C# HttpStatusCode.

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

Content is a virtual method defined in abstract class ApiController, the base of the controller. See the declaration as below:

protected internal virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value);
themefield
  • 3,847
  • 30
  • 32
2

Below code / class really helpful to handle all type of responses. May be success or fail etc.

Why should I use this? :

Suppose I am consuming web API service. There are some possibilities of output as below:

  1. You might not get any result because of validation error
  2. You will get expected result
  3. You will get error.

So here I have solution to handle all the scenarios. Also I tried to maintain uniformity in the output. You can give remark or actual error message. The web service consumer can only check IsSuccess true or not else will sure there is problem, and act as per situation. There should be perfect communication between web API developer and web API consumer. If result is not generating then why. The comment or exception will acknowledge and they will act accordingly. Hence this is best solution for web API consumer / user.

Single response for all all type of results.

  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 Request.CreateResponse(HttpStatusCode.OK, _res);
            }
            catch (Exception ex)
            {
                _res.IsSuccess = false;
                _res.ErrorMessage = ex;
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, _res )); 
            } 
        }

You are welcome to give suggestion if any :)

I am happy if anyone is using and get benefited. Write me if any addition or modification makes this more improved, on akhandagale65@gmail.com.

Amol Khandagale
  • 111
  • 2
  • 5
1

@mayabelle you can create IHttpActionResult concrete and wrapped those code like this:

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
  • 348
  • 6
  • 25
1

this answer is based on Shamil Yakupov answer, with real object instead of string.

using System.Dynamic;

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

return Content<object>(HttpStatusCode.BadRequest, response);
Kugan Kumar
  • 423
  • 1
  • 8
  • 14
1

If you are just looking for sending empty response with specific HTTP code:

return StatusCode(StatusCodes.Status418ImATeapot);
Kevin Dimey
  • 709
  • 6
  • 15
0

I had the same problem. I want to create custom result for my api controllers, to call them like return Ok("some text");

Then i did this: 1) Create custom result type with 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) Create custom controller with new method:

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

And then i can call them in my controllers, like this:

public IHttpActionResult SomeMethod()
    {
       return EmptyResult();
    }
Merchezatter
  • 306
  • 1
  • 6
0

For exceptions, I usually do

 catch (Exception ex)
        {
            return InternalServerError(new ApplicationException("Something went wrong in this request. internal exception: " + ex.Message));
        }
ahsant
  • 1,003
  • 4
  • 17
  • 25
-1

Sorry for the late answer why don't you simple use

return BadRequest("your message");

I use it for all my IHttpActionResult errors its working well

here is the documentation : https://msdn.microsoft.com/en-us/library/system.web.http.apicontroller.badrequest(v=vs.118).aspx

benraay
  • 783
  • 8
  • 14
  • 8
    Because not all errors are the result of bad requests, so a `400` response would be inappropriate. OP specifically gave a `500` response as an example. – user1620220 Dec 01 '16 at 13:37
  • Yes it's only possible with BadRequest the other types don't take a message argument – benraay Mar 06 '17 at 17:03
-1

You can use this:

return BadRequest("No data is present in table!!");