I have an ASP.NET Web API endpoint with controller action defined as follows :
[HttpPost]
public HttpResponseMessage Post([FromBody] object text)
Very late to this party with a grossly simplified solution. I had success with this code in the controller method:
public HttpResponseMessage FileHandler()
{
HttpResponseMessage response = new HttpResponseMessage();
using (var reader = new StreamReader(System.Web.HttpContext.Current.Request.GetBufferedInputStream()))
{
string plainText = reader.ReadToEnd();
} .....}
And on the client side, these are the Ajax options I used:
var ajaxOptions = {
url: 'api/fileupload/' + "?" + $.param({ "key": metaKey2, "File-Operation": "Remove", "removalFilePath": $removalFilePath, "Audit-Model": model, "Parent-Id": $parentId, "Audit-Id": $auditId }),
type: 'POST', processData: false, contentType: false, data: "BOB"
};
In ASP.NET Core 2.0 you simply do the following :-
using (var reader = new StreamReader(Request.Body))
{
string plainText= reader.ReadToEnd();
// Do something else
return Ok(plainText);
}
In some situations it might be simpler to let the JsonMediaTypeFormatter let do the work:
var formatter = GlobalConfiguration.Configuration.Formatters.Where(f=>f is System.Net.Http.Formatting.JsonMediaTypeFormatter).FirstOrDefault();
if (!formatter.SupportedMediaTypes.Any( mt => mt.MediaType == "text/plain" ))
formatter.SupportedMediaTypes.Add( new MediaTypeHeaderValue( "text/plain" ) );
Since Web API doesn't have out of box formatter for handling text/plain, some options:
Modify your action to have no parameters... reason is having parameters triggers request body de-serialization. Now you can read the request content explicitly by doing await Request.Content.ReadAsStringAsync()
to get the string
Write a custom MediaTypeFormatter to handle 'text/plain'... it's actually simple to write in this case and you could keep the parameters on the action.
Purified version using of gwenzek's formatter employing async/await:
public class PlainTextFormatter : MediaTypeFormatter
{
public PlainTextFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
}
public override bool CanReadType(Type type) =>
type == typeof(string);
public override bool CanWriteType(Type type) =>
type == typeof(string);
public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var streamReader = new StreamReader(readStream);
return await streamReader.ReadToEndAsync();
}
public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
{
var streamReader = new StreamWriter(writeStream);
await streamReader.WriteAsync((string) value);
}
}
Please note I intentionally do not dispose StreamReader/StreamWriter, as this will dispose underlying streams and break Web Api flow.
To make use of it, register while building HttpConfiguration:
protected HttpConfiguration CreateHttpConfiguration()
{
HttpConfiguration httpConfiguration = new HttpConfiguration();
...
httpConfiguration.Formatters.Add(new PlainTextFormatter());
...
return httpConfiguration;
}
Actually it's a shame that web API doesn't have a MediaTypeFormatter
for plain text. Here is the one I implemented. It can also be used to Post content.
public class TextMediaTypeFormatter : MediaTypeFormatter
{
public TextMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
}
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var taskCompletionSource = new TaskCompletionSource<object>();
try
{
var memoryStream = new MemoryStream();
readStream.CopyTo(memoryStream);
var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
taskCompletionSource.SetResult(s);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
return taskCompletionSource.Task;
}
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, System.Net.TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
{
var buff = System.Text.Encoding.UTF8.GetBytes(value.ToString());
return writeStream.WriteAsync(buff, 0, buff.Length, cancellationToken);
}
public override bool CanReadType(Type type)
{
return type == typeof(string);
}
public override bool CanWriteType(Type type)
{
return type == typeof(string);
}
}
You need to "register" this formatter in your HttpConfig by something like that:
config.Formatters.Insert(0, new TextMediaTypeFormatter());