34

There's a Request object, and getting the request content type is easy. But how do you specify a content type for the response? My controller looks like this (other actions excised for brevity):

public class AuditController : ApiController
{   
  // GET api/Audit/CSV
  [HttpGet, ActionName("CSV")]
  public string Csv(Guid sessionId, DateTime a, DateTime b, string predicate)
  {
    var result = new StringBuilder();
    //build a string
    return result.ToString();
  }
}

This works fine except that it has the wrong content type. I'd like to do this

Response.ContentType = "text/csv";

A little research reveals that we can type the Action to return an HttpResponseMessage. So the end of my method would look like this:

  var response = new HttpResponseMessage() ;
  response.Headers.Add("ContentType","text/csv");
  response.Content = //not sure how to set this
  return response;

The documentation on HttpContent is rather sparse, can anyone advise me on how to get the contents of my StringBuilder into an HttpContent object?

2 Answers 2

47

You'll have to change the return type of the method to HttpResponseMessage, then use Request.CreateResponse:

// GET api/Audit/CSV
[HttpGet, ActionName("CSV")]
public HttpResponseMessage Csv(Guid sessionId, DateTime a, DateTime b, string predicate)
{
    var result = new StringBuilder();

    //build a string

    var res = Request.CreateResponse(HttpStatusCode.OK);
    res.Content = new StringContent(result.ToString(), Encoding.UTF8, "text/csv");

    return res;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Aha! It was the use of Request.CreateResponse that I needed. Points are all your! (Just looked at MediaTypeFormatter... why would anyone make it so complicated?)
You can leave out "yet"... I'm getting Could not find a formatter matching the media type 'text/csv' that can write an instance of 'String'. which tells me I need to put my build a string logic into a MediaTypeFormatter and associate it with text/csv, and pass the LINQ result to it via CreateResponse. Thanks for getting me over the hump there.
This worked for me when I needed to return "text/xml". Side Note: Twilio webhooks would not handle Parameterization in my ApiController, so I either had to use FormDataCollection (then foreach through that for Parameters) or switch from ApiController back to Controller, for my named Parameters in the Method's signature to be populated by Twilio. I went with the latter (non-WebApi) and use this instead: return Content(result.ToString(), "text/xml")
6

You do not want to return HttpResponseMessage as that returns the response your own Controller Method got from calling a second server's API for data. It just packages up that response into JSON and sends that to your caller. Bad idea!

ASP.NET Core in 2023 has updated the Response Types for Web API and MVC. They have updated the IActionResult type and many subtypes derived from it, including some simpler "helper functions" that wrap the content, content-type, and status code into one Response call. They all allow customizations before sending out the Response. So let's use your text/csv mime-type example, and create one...

This first one is simpler, and allows you to customize the content-type. ContentResult is like JsonResult. Both are specialized for specific data types. ContentResult is used more for text content using the text/plain mime-type delivered in the response. But you can actually change it to deliver other types...

[HttpGet("[action]")]
public ContentResult MyCSV() {
    return new ContentResult {
        Content = "a,b,c",
        ContentType = "text/csv",
        StatusCode = 200
    };
}

This second one is more complex, but allows you to use the raw response object to encode your string, set the content-type and status code, and stream it out to the caller...

[HttpGet("[action]")]
public async Task MyCSV() {
    var mystring = "a,b,c";
    byte[] data = Encoding.UTF8.GetBytes(mystring);
    this.Response.ContentType = "text/csv";
    this.Response.StatusCode = 200;
    await Response.Body.WriteAsync(data, 0, data.Length);
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.