0

I have to create API to read data from JSON file and save it into database. So I did it and it works fine when I send file using Postman. But I also need to be able to do the same operation using form in my view and I cannot figure out solution for it.

ImportController.cs

[Produces("application/json")]
[Route("api/Import")]
public class ImportController : ControllerBase
{

    private readonly DbContext dbContext;

    public ImportController(DbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    [HttpPost]
    [Route("ImportData")]
    public IActionResult ImportData(IFormFile file)
    {

        var content = string.Empty;

        using (var reader = new StreamReader(file.OpenReadStream()))
        {
            content = reader.ReadToEnd();
        }

        List<UserImportModel> userObjects = null;
        try
        {
            userObjects = JsonConvert.DeserializeObject<List<UserImportModel>>(content);
        }
        catch
        {
            return BadRequest();
        }

        foreach (var user in userObjects)
        {

            UserModel us = new UserModel
            {
                Username = user.Username,
                Password = user.Password,
                Created = DateTime.UtcNow
            };

            dbContext.User.Add(us);
            dbContext.SaveChanges();
        }

        return Ok();
    }

Form in my view

    <form method="post" enctype="multipart/form-data" action="../api/Import/ImportData">
         <input type="file" name="file" id="file">
         <input type="submit" value="Upload file" name="submit">
    </form>

When I enter Developer Tools in my browser and click submit, following data is displayed as POST parameters:

-----------------------------209091002211274
Content-Disposition: form-data; name="file"; filename="test.json"
Content-Type: application/json

[{"Username":"user1","Password":"123456"},{"Username":"user2","Password":"654321"}]
-----------------------------209091002211274
Content-Disposition: form-data; name="submit"

Upload file
-----------------------------209091002211274--

It leads me to believe that file and its data is send, is that right?

Kamil
  • 111
  • 13
  • 2
    Do you get an error? Does the `ImportData` action get fired? It's not clear what the problem here is. You might want to take a look at [ASPNetCore - Uploading a file through REST](https://stackoverflow.com/q/50223606) – Heretic Monkey Sep 06 '18 at 14:49
  • Yeah, everything above looks good. The post body you're seeing is what a multipart/form-data encoded body should look like. What is the issue? – Chris Pratt Sep 06 '18 at 14:52
  • @kamil - What does your IFormFile interface look like? – Chris Sep 06 '18 at 14:52
  • @Chris: `IFormFile` is from the ASP.NET Core framework. It's not his. There's no issue there. – Chris Pratt Sep 06 '18 at 14:53
  • @ChrisPratt - if Kamil is trying ot pass both a username, password and a form to the end point which is just expecting a form, then he's gotta do something to accept the username and password on that endpoint. Creating a new object to accept all 3 items on the post would help out greatly. – Chris Sep 06 '18 at 14:56
  • @Chris: I think you misread his code. That information is coming from the *contents* of the JSON file. The post is merely upload the JSON as a file, not each individual record. Put another way, he's not posting JSON, he's posting a file that just happens to contain JSON. – Chris Pratt Sep 06 '18 at 15:05
  • @HereticMonkey - I don't get any error and `ImportData` action is not fired. I tried to use solutions from link you posted, but only one last works, I mean body of my request is read properly. – Kamil Sep 06 '18 at 15:13
  • @HereticMonkey - Maybe that's the way, but there is issue in `userObjects = JsonConvert.DeserializeObject>(body);`, because userObjects remains null after that. Maybe it's because of "not-clear" JSON: `"-----------------------------914163675013\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test.json\"\r\nContent-Type: application/json\r\n\r\n[{\"Username\":"user1",\"Password\":\"123456\"}]\r\n-----------------------------914163675013\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nUpload file\r\n-----------------------------914163675013--\r\n"` – Kamil Sep 06 '18 at 15:14
  • @ChrisPratt - My bad, I was looking at the header - name="file"; filename="test.json" - and assuming that was the content being posted. – Chris Sep 06 '18 at 15:16
  • 1
    Yeah, don't use the straight request body; then you have to parse multipart/formdata and that's kind of a pain. Just make your parameter `[FromForm] IFormFile file` and it should work... That was the takeaway from that article I linked. – Heretic Monkey Sep 06 '18 at 15:20
  • @HereticMonkey - I did it using this way and it still didn't work, but then I copied code from link you previously posted and it worked, so I started adding new stuff from my method and after all it still worked. Then I copied stuff to my method and it didn't. It turned out that reason of it was presence of `[Authorize(AuthenticationSchemes = "Bearer")]` parameter. Looks like calling API directly from form is not that good idea... I think I will pass this file to some UI method and then call API method from there. Would it be good idea? Thank you very much for help. – Kamil Sep 06 '18 at 15:50
  • 1
    If it works, it is good :). You might want to consider using ajax to post the form instead, then you can set headers like Authorization. That would be the more canonical way of doing it, but going back to the UI server is also perhaps more secure. Good luck! – Heretic Monkey Sep 06 '18 at 15:57

1 Answers1

0

I think it is because it is an array [ ] of objects rather than a JSON collection { }

Aaron Reese
  • 131
  • 11
  • An array is a collection. Curly brackets `{ }` indicate an object. – Heretic Monkey Sep 06 '18 at 15:14
  • pedant :). What I mean is that the top-level collection is using the array syntax of [] rather then it being a JSON object that is actually a collection of smaller JSON objects - come back XML,all is forgiven – Aaron Reese Sep 06 '18 at 15:21
  • Not being pedantic, just being realistic. There's nothing wrong with the JSON presented. An object cannot be a collection of other objects; they would have to be properties of the outer object, and the OP obviously wants a `List` out of it, which is properly represented as an array `[ ]` of objects. – Heretic Monkey Sep 06 '18 at 15:24
  • 1
    @AaronReese this could be a comment instead of an answer. – Lewis86 Sep 06 '18 at 16:10