1

I need to receive a content together with a byte array in a c# ASP.NET Core Web API application.

**--HttpClient (console Application)**  

                Dictionary<int, byte[]> fileparts = new Dictionary<int, byte[]>();
                int bufferSize = 1000 * 1024;

                byte[] buffer;
                string filePath = @"D:\Extra\Songs\test.mp3";
                using (FileStream fileData = File.OpenRead(filePath))
                {
                    int index = 0;
                    int i = 1;
                    while (fileData.Position < fileData.Length)
                    {

                        if (index + bufferSize > fileData.Length)
                        {
                            buffer = new byte[(int)fileData.Length - index];
                            fileData.Read(buffer, 0, ((int)fileData.Length - index));
                        }
                        else
                        {
                            buffer = new byte[bufferSize];
                            fileData.Read(buffer, 0, bufferSize);
                        }

                        fileparts.Add(i, buffer);
                        index = (int)fileData.Position;
                        i++;
                    }
                }
                
 while (fileparts.Count() != 0)
 {               
      var data = fileparts.First();          
  var fileContent = new ByteArrayContent(data);//byte content
    fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "test" };
                        fileContent.Headers.Add("id", id);
                        fileContent.Headers.Add("name", name);
                        fileContent.Headers.Add("length", length);
                        if (fileparts.Count() == 1)
                          fileContent.Headers.Add("IsCompleted", "true");
                        else
                          fileContent.Headers.Add("IsCompleted", "false");
                          
                    using (var content = new MultipartFormDataContent())
                    {
                       content.Add(fileContent);
                       // Make a call to Web API 
                        var result = client.PostAsync("/api/file", fileContent).Result;
                        if (result.StatusCode == System.Net.HttpStatusCode.OK)
                            fileparts.Remove(data.Key);
                    }

**--WebApi Core ApiController**

    public class FileController : Controller
    {
        [HttpPost]
        public async Task<IActionResult> Post()
        {
    /*i need to get the content here , for some reason existing .NET libraries does not work here
    like 
        MultipartMemoryStreamProvider provider = new MultipartMemoryStreamProvider();
        FilePart part = null;
       
        await Request.Content.ReadAsMultipartAsync(provider); -- request.content not available 
        using (Stream fileStream = await provider.Contents[0].ReadAsStreamAsync())
                {
                    part = provider.Contents[0].Headers.GetData(); //public static FilePart GetData name,length,id 
                    part.Data = fileStream.ReadFully();
    */    
    }
the back end I have working but can't find a way of the new asp.net core controller parsing fileobject and data from client post through to the service! Any ideas would be greatly appreciated as always...
Lakmal
  • 779
  • 1
  • 8
  • 16

2 Answers2

3

You can modify your controller action method like below to accept ByteArrayContent OR MultipartFormDataContent as required. I have used [FromBody] attribute for the model binding in POST.

Here is more info on [FromBody]

https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

public class FileController : Controller
    {
        [HttpPost]
        public async Task<IActionResult> Post([FromBody] MultipartFormDataContent content)
        {
         MultipartMemoryStreamProvider provider = new MultipartMemoryStreamProvider();
        FilePart part = null;
         // access the content here 
         await content.ReadAsMultipartAsync(provider);
        // rest of the code
       }
   }

as discussed before you should be using content to post to this API like below

var result = client.PostAsync("/api/file", content).Result;

Niladri
  • 5,832
  • 2
  • 23
  • 41
  • 1
    With [FromBody] attribute client exit with 'UnsupportedMediaType', it seems not reach the server side POST. – Lakmal Oct 17 '17 at 19:35
  • @Lakmal which version of web api are you using ? – Niladri Oct 17 '17 at 19:44
  • @Lakmal have you changed it to `var result = client.PostAsync("/api/file", content).Result;` – Niladri Oct 17 '17 at 19:45
  • you mean "Microsoft.AspNet.WebApi.Client": "5.2.3", "Microsoft.AspNetCore.Mvc": "1.0.1" ? – Lakmal Oct 17 '17 at 19:47
  • Yes, var result = client.PostAsync("/api/file", content).Result; – Lakmal Oct 17 '17 at 19:49
  • I tried it without [FromBody] attribute (Post(MultipartFormDataContent content)). and then read all contents of multipart message into MultipartMemoryStreamProvider (await content.ReadAsMultipartAsync(provider)) but provider.Contents[0] is missing – Lakmal Oct 17 '17 at 19:53
  • is that version issue or something else ? – Lakmal Oct 17 '17 at 20:20
  • @Lakmal it does not seem like a version issue for byte array in web api 2 we had "bson" formatter which you needed to add as mediatypeformatter but in .net core I am not sure if it's still there. Are you using JSON.NET? then you can try to serialize the input and then try – Niladri Oct 18 '17 at 07:19
  • Same exception as @Lakmal UnsupportedMediaType on core 2.2 – flux Feb 26 '19 at 16:29
2

I've used this sucessfully in the past:

[HttpPost]
public async Task<IActionResult> Post(IFormFile formFile)
{
    using (Stream stream = formFile.OpenReadStream())
    {
         //Perform necessary actions with file stream
    }
}

I believe you'll also need to change your client code to match the parameter name:

fileContent.Headers.Add("name", "formFile");

alec
  • 396
  • 1
  • 6