2

Ultimately I want to have a simple file upload page using as basic a jQuery code as possible with the c# code on the server but I keep receiving a null IFormFile on the server.

There are lots of examples of how this can work with an Ajax POST with Form-data and receiving an IFormFile on an ASP.NET Web API controller action. However, it seems every one of them has had to try multiple tweaks to the code to get theirs working.

I have made a simple solution with just the API part and using Postman to send a file to it. I have tried different combinations of Content-Type and Accept headers but I always receive a null file.

To satisfy some hosting requirements, I am using OWIN to self-host the application. Here is the controller code, I have used the default values controller and edited the post-action...

    public string Post([FromBody]IFormFile file)
    {
        if (file != null)
        {
            return "Success: We got something!!!";
        }
        else
        {
           return "ERROR: We got nothing :-(";
        }

     }

My StartUp.cs configuration is below. Although my example shows multipart/form-data, I have also tried application/JSON and other formats including leaving those blank.

public void Configuration(IAppBuilder app)
        {
            var config = new HttpConfiguration();
            config.Routes.MapHttpRoute("default", "{controller}");
            config.EnableCors();

            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
        }

Then here are 2 screenshots of my latest postman attempt. I have hastily put them up on a Wix server so apologies if they are not yet visible

The Body

The Header

At this point, I'll be happy for the Post method to receive a not null value for a file.

Wyck
  • 10,311
  • 6
  • 39
  • 60
Roland
  • 85
  • 3
  • 11

1 Answers1

2

Use [FromForm] attribute instead of [FromBody] and remove both Accept and Content-Type headers.

EDIT:

So it appears that in haste I immediately assumed you are using ASP.NET Core (despite you pointing out otherwise) since IFormFile is Microsoft.AspNetCore.Http namespace class so naturally this explains why it doesn't work when you are trying this on .NET Framework.

I suppose technically it would be possible to create a concrete implementation of this ASP.NET Core interface and then some special case model binder, but this would certainly require some work.

I am not sure where you found these examples for making IFormFile work in .NET Framework but I could'nt find any example.

The closest experience to ASP.NET Core IFormFile binding that I could find was this ApiMultipartFormFormatter, which is super easy to implement and supports HttpFile binding. One thing that is not immediately obvious is that you will need to wrap some HttpFile property into another class to make it work.

public string Post([FromForm]MyViewModel vm)
{
    if (vm.file != null)
    {
        return "Success: We got something!!!";
    }
    else
    {
        return "Sadness: We got null :-(";
    }
}

public class MyViewModel
{
    public HttpFile SomeFile { get; set; }
}
Vidmantas Blazevicius
  • 4,652
  • 2
  • 11
  • 30
  • Thanks for the response Vimantas but I am still getting a null file. Anything else you can see? Are you able to try this on your machine? – Roland Jul 20 '19 at 15:08
  • Ive tried it before answering and had no issues to get the file binding first time. – Vidmantas Blazevicius Jul 20 '19 at 15:15
  • Hmmm, would you mind putting your solution on GitHub as there's clearly something I'm missing. – Roland Jul 20 '19 at 21:59
  • I will try when i get back to work on monday if you still haven’t solved it yourself. – Vidmantas Blazevicius Jul 20 '19 at 23:05
  • Thanks much. Here's a complete [solution](https://github.com/Sothecom/FileUpload). Once the FileReceiver.SelfHost is set as the default project, and you are not already using port 5015, you should be able to run http://localhost/upload.html, which will try to post your selected file to http://localhost:5015/values – Roland Jul 21 '19 at 00:17
  • I've been putting off migrating partially or fully to core, I've decided this is probably a good point to start. Thanks a lot. I did give the apimultipartformformatter too but I couldn't get it working. Hoping to report some good news tomorrow – Roland Jul 22 '19 at 21:49
  • What was not working? I only changed like few lines in your code to make it work. – Vidmantas Blazevicius Jul 23 '19 at 07:55
  • Changing the parameter to a class meant that I got a new object (as opposed to null), but the property within was still always null. Were you getting the actual file? Did you need to alter the ajax? – Roland Jul 23 '19 at 13:00
  • I tried it through postman, I had to add the `config.Formatters.Add(new MultipartFormDataFormatter());` in the `WebApiConfig.cs` file – Vidmantas Blazevicius Jul 23 '19 at 13:02
  • Got it sending through Postman directly to a clone of ApiMultipartFormData so yeay!!! Now just trying to replicate in ajax – Roland Jul 25 '19 at 01:12
  • Just replicate the headers and form encoding, else should work out of the box as well. – Vidmantas Blazevicius Jul 25 '19 at 07:49
  • Still fighting with it... The postman headers seem pretty startforward… [Screenshot](https://static.wixstatic.com/media/25c81a_c2be2b277f214cc092941d810e1d3c91~mv2.jpg/v1/fill/w_1077,h_542/Working%20Postman.JPG.jpg) – Roland Jul 25 '19 at 17:04
  • So I took a holiday (not because of this issue :-D), came back to it with fresh eyes, an realised the transportation part was working a long time ago, but I somehow expected the javascript file to be automatically transformed into the HttpFile - not so. This post helped a lot [https://stackoverflow.com/questions/32556664/getting-byte-array-through-input-type-file](https://stackoverflow.com/questions/32556664/getting-byte-array-through-input-type-file) One restriction I found so far though, is that the files over 700Mb don't send. – Roland Aug 19 '19 at 10:37
  • Good to know that you have managed to close this one off. Always helps to take a break :) – Vidmantas Blazevicius Aug 19 '19 at 10:40