I'm trying to upload a simple byte array for my Web Api controller (ASP.NET Core 3)
using var client = new HttpClient() { BaseAddress = new Uri("http://someUrl.com/") };
var body = new ByteArrayContent(new byte[] {1, 2, 3});
var result = await client.PostAsync("api/somecontroller/content?someField=someData", body);
Controller
[HttpPost("content")]
public IActionResult Upload([FromBody]byte[] documentData, [FromQuery] string someField)
{
...
return Ok();
}
but this gives me the error 415 Unsupported media type
. Why ? I need to put some additional data in the url, but I don't think that's the issue here.
While byte[]
would be a great way to represent application/octet-stream
data, this is not the case by default in asp.net core Web API.
Here is a simple workaround:
Send request by HttpClient:
using var client = new HttpClient() { BaseAddress = new Uri("http://localhost:62033") };
var body = new ByteArrayContent(new byte[] { 1, 2, 3 });
body.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
var result = await client.PostAsync("api/Values/content?someField=someData", body);
Receive action in Web Api project:
[HttpPost("content")]
public IActionResult Upload([FromBody]byte[] documentData, [FromQuery] string someField)
{
return Ok();
}
Custom InputFormatter in Web Api Project:
public class ByteArrayInputFormatter : InputFormatter
{
public ByteArrayInputFormatter()
{
SupportedMediaTypes.Add(Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"));
}
protected override bool CanReadType(Type type)
{
return type == typeof(byte[]);
}
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var stream = new MemoryStream();
await context.HttpContext.Request.Body.CopyToAsync(stream);
return InputFormatterResult.SuccessAsync(stream.ToArray());
}
}
Startup.cs in Web Api Project:
services.AddControllers(options=>
options.InputFormatters.Add(new ByteArrayInputFormatter()));
Result:
The issue is caused by the [FromBody] attribute which supports only simple types. You can use Type Converters for other types. The correct controller action code should be:
[HttpPost("content")]
public IActionResult content([FromQuery] string someField)
{
var documentData= new byte[Request.ContentLength.Value];
Request.Body.ReadAsync(documentData);
//...
return Ok();
}
Be aware that the answer above has typos, which may cost you quite a lot of time (code in the gif file is incorrect and may produce damaged not complete byte arrays):
public async override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var stream = new MemoryStream();
await context.HttpContext.Request.Body.CopyToAsync(stream);
return InputFormatterResult.Success(stream.ToArray());
}
Based on the excellent answer from @Rena you can also use the following class to read the request body as a Stream
parameter:
public class StreamInputFormatter: InputFormatter
{
public StreamInputFormatter()
=> SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/octet-stream"));
protected override bool CanReadType(Type ArgType) => ArgType == typeof(Stream);
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext ArgContext)
=> InputFormatterResult.SuccessAsync(ArgContext.HttpContext.Request.Body);
}
Your API controller action can then look something like this:
[HttpPost]
[Consumes("application/octet-stream")]
public async Task<ActionResult> UploadData([FromBody] Stream ArgData) {}
When you do the above and use Swagger UI via the Swashbuckle.AspNetCore
package, it will correctly show a file-input control which allows you to upload the binary data:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With