How to submit a post request with files and json?

Asked

Viewed 1,618 times

1

I have a form to send data to my server.

In this form I have some input fields and a file upload.

This is the sending of my form.

submit () {
  console.log(this.banners)
  const banners = new FormData()
  banners.append('banners', this.banners)
  this.$axios.post(api.insertBanner, banners).then(response => response.data)
    .catch(error => {
      console.log(error)
    })
},

console.log(this.banners) results in:

inserir a descrição da imagem aqui

My POST method:

public async Task<ActionResult> Post(BannersDTO banners)

Bannersdto.Cs

public class BannersDTO
{
    public Microsoft.AspNetCore.Http.IFormFile Files { get; set; }
    public string TermoOrSku { get; set; }
    public bool InserirImediato { get; set; }
    public string DataAtivacao { get; set; }
    public string DataVigencia { get; set; }
}

Problem: I have received status code 400(badRequest), that is, I need to modify the input because it is not correct. What is wrong?

If I modify the code parts:

public async Task<ActionResult> Post(Microsoft.AspNetCore.Http.IFormFile Files)

banners.append('files', this.banners.files)

My code works fine, but in case I just get the file, and I also need the data.

1 answer

1


I ended up resorting to a code not very familiar(I was just sent a link with a code ready).

Explaining:

Create a custom model:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

namespace TestMultipart.ModelBinding
{
    public class JsonWithFilesFormDataModelBinder : IModelBinder
    {
        private readonly IOptions<MvcJsonOptions> _jsonOptions;
        private readonly FormFileModelBinder _formFileModelBinder;

        public JsonWithFilesFormDataModelBinder(IOptions<MvcJsonOptions> jsonOptions, ILoggerFactory loggerFactory)
        {
            _jsonOptions = jsonOptions;
            _formFileModelBinder = new FormFileModelBinder(loggerFactory);
        }

        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));

            // Retrieve the form part containing the JSON
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName);
            if (valueResult == ValueProviderResult.None)
            {
                // The JSON was not found
                var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName);
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message);
                return;
            }

            var rawValue = valueResult.FirstValue;

            // Deserialize the JSON
            var model = JsonConvert.DeserializeObject(rawValue, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings);

            // Now, bind each of the IFormFile properties from the other form parts
            foreach (var property in bindingContext.ModelMetadata.Properties)
            {
                if (property.ModelType != typeof(IFormFile))
                    continue;

                var fieldName = property.BinderModelName ?? property.PropertyName;
                var modelName = fieldName;
                var propertyModel = property.PropertyGetter(bindingContext.Model);
                ModelBindingResult propertyResult;
                using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel))
                {
                    await _formFileModelBinder.BindModelAsync(bindingContext);
                    propertyResult = bindingContext.Result;
                }

                if (propertyResult.IsModelSet)
                {
                    // The IFormFile was sucessfully bound, assign it to the corresponding property of the model
                    property.PropertySetter(model, propertyResult.Model);
                }
                else if (property.IsBindingRequired)
                {
                    var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName);
                    bindingContext.ModelState.TryAddModelError(modelName, message);
                }
            }

            // Set the successfully constructed model as the result of the model binding
            bindingContext.Result = ModelBindingResult.Success(model);
        }
    }
}

Add as a Dataannotationion

Banners.DTO

using Microsoft.AspNetCore.Mvc;

namespace LR.Manager.Banner.Entidades
{
    [ModelBinder(typeof(JsonWithFilesFormDataModelBinder), Name = "json")]
    public class BannersDTO
    {
        public Microsoft.AspNetCore.Http.IFormFile Files { get; set; }
        public string TermoOrSku { get; set; }
        public bool InserirImediato { get; set; }
        public string DataAtivacao { get; set; }
        public string DataVigencia { get; set; }
    }
}

On the controller:

[HttpPost]
 public async Task<ActionResult> Post(BannersDTO banners)
 {

Modify the request:

submit () {
  let data = {}
  const { termoOrSku, inserirImediato, dataAtivacao, dataVigencia } = this.banners
  data.termoOrSku = termoOrSku
  data.inserirImediato = inserirImediato
  data.dataAtivacao = dataAtivacao
  data.dataVigencia = dataVigencia

  const files = new FormData()
  files.append('files', this.banners.files)
  files.append('json', JSON.stringify(data))
  this.$axios.post(api.insertBanner, files).then(response => response.data)
    .catch(error => {
      console.log(error)
    })
},

See that I had to create a form-data with the File and another with JSON. For the little I understood of the customized model the json is deserialized and a map property is made property by property.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.