-1

I have Controller and Action for editing Person table.

I'm filling form with information and if user changes anything I enabling Save button to call action.

Person contains information and profile picture.

Problem is, Action is called only when I browse profile picture and have form sent as multipart/form-data. But if I calling it without sending file, just form I getting error 500.

If I want to send it as application/json and bind it to a model I must use [FromBody] annotation in Action for PersonModel parameter.

Now I sending multipart/form-data - and it only binds If I upload new picture, if I change only input fields - I'm getting error 500.

[Route("EditPerson")]
[HttpPost]
public IActionResult EditPerson(PersonDto Person) {
   //Do something with person model
   return Ok();
}

And I'm using jQuery-Form-Plugin:

 $('#personEditForm').ajaxSubmit({
      url: 'PersonSettings/EditPerson',
     type: 'post',
     contentType: 'multipart/form-data',
     success: successEditPerson,
     resetForm: true,
     beforeSubmit: beforeEditPerson
});

Form:

 <form id="personEditForm" >
                <h6><b>General</b></h6>
                <hr/>
                <fieldset>
                    <div class="row">
                        <div class="col-md-4">
                            <div class="form-group">
                                <label for="Name">
                                    Person Name :
                                    <span class="danger">*</span>
                                </label>
                                <input autocomplete="off" type="text" class="form-control required" id="NameEdit" name="Name">
                            </div>
                        </div>
                        <div class="col-md-4">
                            <div class="form-group">
                                <label for="Surename">
                                    Person Surename :
                                    <span class="danger">*</span>
                                </label>
                                <input autocomplete="off" type="text" class="form-control required" id="SurenameEdit" name="Surename">
                            </div>
                        </div
                        <div class="col-md-4">
                            <div class="form-group">
                                <label for="Age">
                                    Person Age :
                                    <span class="danger">*</span>
                                </label>
                                <input autocomplete="off" type="text" class="form-control required" id="AgeEdit" name="Age">
                            </div>
                        </div
                        <div class="col-md-4">
                            <div class="form-group">
                                <label for="PersonPic">
                                    Profile pic (Must be in size ..x..) :
                                    <span class="danger">*</span>
                                </label>
                                <input type="file" class="form-control" id="PersonPic" name="PersonPic" accept="image/*" onchange="loadImageEdit(event)">
                            </div>
                        </div>
                        <div class="col-md-4 ">
                            <div class="form-group">
                                <label for="Name">
                                    Profile picture preview:
                                </label>
                                <img id="personImagePreviewEdit" alt="Upload image to preview" style="display: block"src="#"/>
                            </div>
                        </div>
                    </div>
                </fieldset></form>

I'm using beforeEditPerson function to append Id for Person.

ElementW
  • 29
  • 8
  • don't set `contentType: 'multipart/form-data'` explicitly. It needs to have a "boundary" value set as well, which the browser will handle. Just remove this line and try again, I think it should help. Can you please also show us the HTML of your form. BTW I cannot see why you think any JSON is being posted. It should just submit a mult-part request consisting of the file data and then the other parameters in the usual form-url-encoded format. – ADyson Sep 05 '18 at 12:02
  • Tried, don't work.. I will edit my answer with form – ElementW Sep 05 '18 at 12:10
  • Possible duplicate of [Multipart/form-data images upload with JSON asp.net core api](https://stackoverflow.com/questions/51614373/multipart-form-data-images-upload-with-json-asp-net-core-api) – Alex Riabov Sep 05 '18 at 12:26
  • "didn't work" means what exactly? Same behaviour as you already described, or something different? By the way what is the 500 error? Your should be able to debug the server or look in logs to see what the underlying problem was. That might help. – ADyson Sep 05 '18 at 12:45

2 Answers2

2

You cannot send both multipart/form-data and application/json encoded requests to the same action. The modelbinder needs to know in advance how to handle the request body, requiring the specification of either [FromForm] (the default) or [FromBody]. If you need to handle both, then you need two separate actions, though you can factor out the actual logic to stay DRY. For example:

private IActionResult EditPersonCore(PersonDto person)
{
   //Do something with person model
   return Ok();
}

[HttpPost("EditPersonForm"]
public IActionResult EditPersonForm(PersonDto person) => EditPersonCore(person);

[HttpPost("EditPersonJson"]
public IActionResult EditPersonJson([FromBody]PersonDto person) => EditPersonCore(person);

Obviously, that means you'll have two different routes, but that's the best you can do.

That said, you don't need to post as multipart/form-data simply because you have a file. You can post a file via JSON; it simply needs to be sent as a Base64-encoded byte array. In JavaScript, you can do that via:

var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
    // here `reader.result` will hold your file as base64
};

Server-side, you then simply need to bind to a property of type byte[]. The modelbinder in ASP.NET Core will transparently deserialize the Base64-encoded string into a byte[].

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
-2

You can check request is contain Multipart content or not so accordingly, you can process the same. if contain the multipart data then do your logic here

   [HttpPost]
    public IActionResult Index([FromBody] personalInfo)
    {
        //check for multipart request
        if (MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
         {                  
              // request for uploaded files 
              var file = Request.Form.Files[0];
         }

     }
Nemi Chand
  • 138
  • 1
  • 10