6

How to POST both images and JSON at the same time in a single POST ? (using multipart) I have a form with some data that i put into JSON and the users can add 0 to 6 photos and submit it to the API.

Can someone explain me how to do it ?

Edit : Here is my code thanks to your help :

    // POST api/<controller>
    [HttpPost, Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public IActionResult Post(ViewModel vm)
    {
        IActionResult response = Unauthorized();

        var data = vm.FamilleProduit;
        var reforigine = vm.RefOrigine;

        if (vm.Images != null)
        {
            foreach (var image in vm.Images)
            {
                byte[] fileData = null;

                // read file to byte array
                using (var binaryReader = new BinaryReader(image.OpenReadStream()))
                {
                    fileData = binaryReader.ReadBytes((int)image.Length);
                }
            }
        }
        return response;
    }

    public class ViewModel
    {
        public string FamilleProduit { get; set; }
        public string RefOrigine { get; set; }
        public List<IFormFile> Images { get; set; }
    }

I'm testing with Postman and i POST 2 text (FamilleProduit & RefOrigine) and 2 files (2 images) with "multipart/form-data". I get the 2 texts perfectly but Images field is null everytime.

Thanks, Tristan.

4
  • "best" is a bit subjective, but one option is to just transmit everything as JSON, the images can be encoded as base64 and placed into properties within the JSON Commented Jul 31, 2018 at 13:59
  • Sending everything as JSON could be an option but i work with a mobile developer and he use multipart. Commented Jul 31, 2018 at 14:04
  • well it depends if you can modify the API to accept any particular format, and whether the other developer is happy to modify their code to comply with the required format. Commented Jul 31, 2018 at 14:06
  • I'll have a look into it. Thanks Commented Jul 31, 2018 at 14:17

1 Answer 1

5

You can use built-in class IFormFile to easily work with file upload. To use it together with JSON you may create custom model binder and combine it together in DTO object:

public class ViewModel
{
    [ModelBinder(BinderType = typeof(FormDataJsonBinder))]
    public DataModel Data { get;set; }

    public List<IFormFile> Images { get; set; }
}

public class FormDataJsonBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if(bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }    

        string fieldName = bindingContext.FieldName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);

        if(valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }
        else
        {
            bindingContext.ModelState.SetModelValue(fieldName, valueProviderResult);
        }    

        string value = valueProviderResult.FirstValue;
        if(string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        try
        {                
            object result = JsonConvert.DeserializeObject(value, bindingContext.ModelType);
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        catch(JsonException)
        {
            bindingContext.Result = ModelBindingResult.Failed();
        }

        return Task.CompletedTask;
    }
}

Then you can work with it in your controller:

[HttpPost]
public IActionResult Create(ViewModel vm)
{
    var data = vm.Data;

    if (vm.Images != null)
    {
        foreach(var image in vm.Images)
        {
            byte[] fileData = null;

            // read file to byte array
            using (var binaryReader = new BinaryReader(image.OpenReadStream()))
            {
                fileData = binaryReader.ReadBytes((int)image.Length);
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

8 Comments

I tried with your code, i retrieve the Data but the "Images" is null when i test with postman. Do you know where it can come from ? i'll post my code if needed.
@TristanSébillet Keys in form-data should match property name
oh f.. I'm tired and i missed it, thanks for the reminder ! have a great day it works perfectly :)
@TristanSébillet can you tell me how you test with postman? I'm trying to do the same, but every time I receive "The input was not valid." I already check the keys names. Thanks!
Nevermind, there was a header [{"key":"Content-Type","value":"application/x-www-form-urlencoded"}] on postman, my mistake
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.