TommyGunn32
TommyGunn32

Reputation: 934

Display content string from HttpResponseMessage

I have a post controller in an MVC app returning this response:

return new HttpResponseMessage(HttpStatusCode.Accepted)
{
    Content = new StringContent("test")
};

When I hit the post URL with this code:

using (WebClient client = new WebClient())
{
    string result = client.UploadString(url, content);
}

result contains this response:

StatusCode: 202, ReasonPhrase: 'Accepted', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Content-Type: text/plain; charset=utf-8 }

Why isn't "test" appearing after Content:?

Thanks!

Upvotes: 2

Views: 1576

Answers (1)

CodeFuller
CodeFuller

Reputation: 31312

You should not return HttpResponseMessage from ASP.NET MVC action. In this case you'll get messy response like this:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcRHJvcGJveFxwcm9nXFN0YWNrT3ZlcmZsb3dcZG90TmV0XE12Y0FwcGxpY2F0aW9u?=
X-Powered-By: ASP.NET
Date: Sun, 04 Feb 2018 10:18:38 GMT
Content-Length: 154

StatusCode: 202, ReasonPhrase: 'Accepted', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
  Content-Type: text/plain; charset=utf-8
}

As you see, you actually get 200 HTTP response with HttpResponseMessage details in response body. This messy body content is what you deserialize into result variable.

ASP.NET MVC actions should return an instance of the class derived from System.Web.Mvc.ActionResult. Unfortunately, there is no built-in action result that allows setting both return status code and body content. There is ContentResult class that allows to set return string content with status code of 200. There is also HttpStatusCodeResult that allows setting arbitrary status code but the response body will be empty.

But you could implement your custom action result with settable status code and response body. For simplicity, you could base it on ContentResult class. Here is a sample:

public class ContentResultEx : ContentResult
{
    private readonly HttpStatusCode statusCode;

    public ContentResultEx(HttpStatusCode statusCode, string message)
    {
        this.statusCode = statusCode;
        Content = message;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        base.ExecuteResult(context);
        HttpResponseBase response = context.HttpContext.Response;
        response.StatusCode = (int)statusCode;
    }
}

The action would look like:

public ActionResult SomeAction()
{
    return new ContentResultEx(HttpStatusCode.Accepted, "test");
}

Another possible fix is to change your controller from MVC to WEB API controller. To make this - just change base class of controller from System.Web.Mvc.Controller to System.Web.Http.ApiController. In this case you could return HttpResponseMessage as in your answer.

In both cases you will get correct HTTP response with 202 status code and string in the body:

HTTP/1.1 202 Accepted
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcRHJvcGJveFxwcm9nXFN0YWNrT3ZlcmZsb3dcZG90TmV0XE12Y0FwcGxpY2F0aW9u?=
X-Powered-By: ASP.NET
Date: Sun, 04 Feb 2018 10:35:24 GMT
Content-Length: 4

test

Upvotes: 1

Related Questions