2

I'm writing an API for mobile clients and an AngularJS web front end using ASP.NET 5. Everything's going well, but I'm stumped on how to create a POST to upload files to the server.

The best info I've found is in this thread. Based on the research I've done, I want to do something like the following, but I keep getting shot down by VS2015 and it's inability to find proper references.

    [HttpPost("card/{cardId}/image")]
    public async Task<IActionResult> Upload()
    {
        var provider = new MultipartMemoryStreamProvider();
        await Request.Body.ReadAsMultipartAsync(provider);
        foreach (var file in provider.Contents)
        {
            var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
            var buffer = await file.ReadAsByteArrayAsync();
            //Do whatever you want with filename and its binaray data.
        }
        return Json (new { Message = "Hooray!" });
    }

...and here's what VS2015 makes of it:

VS2015 issues

With DNXcore5.0 it seems that MultipartMemoryStreamProvider which is part of System.Net.Http can't be found in the namespace, and Request.Body doesn't work with ReadAsMultipartAsync (which couldn't be found anyway, because it's in that System.Net.Http space...)

Is there a better way to set up an API POST to accept files in ASP.NET 5? Or how do we now reference things like System.Net.Http that have worked for years?

Community
  • 1
  • 1
waffles
  • 1,386
  • 12
  • 18
  • You can try to use `public async Task Upload(IFormFile file) {var stream = file.OpenReadStream(); ...}` and then to use `stream.CopyToAsync()` to read the file or just to use `await file.SaveAsAsync("testFilename");` at the beginning. – Oleg Dec 26 '15 at 22:57
  • 1
    Hi Oleg, I can't get that to work. I can see that I have data in Request.Body, but I don't know how to get it into a format I can use because it contains both the file content AND the header info (filename, type, etc). Writing it directly to a file causes an unreadable file to be created because of this extra data. I can't imagine writing my own parser is the right thing to do...there has to be some ASP.NET supported way! – waffles Dec 27 '15 at 00:20
  • My problem: I don't use file upload myself, I just try to help you. Do you tried to use `public async Task Upload(IFormFile file) {...}` Do you get the method called with `file` initialized? The `file` should contains the information which you need. You can use for example `var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);` to get the information about the filename. You need just use the parameter of the type `IFormFile` or `IEnumerable` (or `ICollection`) in case of multiple files. – Oleg Dec 27 '15 at 00:32

1 Answers1

0

In MVC6, you may use IFormFile to handle file upload from your web app.

public IActionResult UploadFiles(IEnumerable<IFormFile> logos)
{
    foreach (var file in logos)
    {
        if (file != null)
        {
           var fileName = string.Empty;

         //If you want to get file name etc, You can read it from the ContentDisposition
         var c= logo.ContentDisposition;
         var meta = c.Split(';').ToList();
         var fileNameMeta = meta.FirstOrDefault(s => s.StartsWith(" filename"));
           if(!String.IsNullOrEmpty(fileNameMeta))
           {
              fileName = fileNameMeta.Split('=')[1];
           } 
           // use fileName as needed

           logo.SaveAs("MyUploads/myUniquefileName.png");
        }
    }
    return View(); // or some JSON as needed
}

Assuming your input file element's has the name logos.

<form asp-action="UploadFiles" asp-controller="Home" enctype="multipart/form-data">
    <input type="file" name="logos" />
    <input type="file" name="logos" />
    <input type="submit" />
</form>

IFormFile is defined in the Microsoft.AspNet.Http namespace which is in Microsoft.AspNet.Http.Abstractions assembly.

If you want to do the file upload via ajax, take a look at this answer.

And for your mobile app, You probably need to convert the file to a base64 string (inside your mobile app) and send it to your action method. You will read the string value and convert it back to bytearray or file from the base64string.

EDIT : In AspNet Core 1, you can still use IFormFile. It comes from Microsoft.AspNetCore.Http namespace. Also you do not need to read the ContentDisposition data yourself to get the file name as there is a FileName property to get you the file name.

if (file != null)
{
   var fileName = file.FileName;
}
Community
  • 1
  • 1
Shyju
  • 214,206
  • 104
  • 411
  • 497
  • 1
    Thanks for the link to the other thread - there's relevant info in that thread for me. Since I'm using an AngularJS front end (as well as mobile apps), the API needs to work without the "form asp-action..." stuff, as I don't have forms or asp-actions... – waffles Dec 27 '15 at 19:01
  • Then take a look at the other answer i linked in this answer. That has an example of posting data via ajax. Also there are some free async file upload directives out there to help you. Just google for it. – Shyju Dec 27 '15 at 19:08
  • I am trying to upload a file using api which takes IFormFile as parameter but am unable to do it. Because client in my case is WPF and not web application. Please see if you have idea about this. I have put a question already: http://stackoverflow.com/questions/35718662/upload-file-in-wpf-application-using-a-web-api-which-expects-iformfile-parameter – Randeep Singh Mar 01 '16 at 12:33