Uploading a file from web form to server requires a different approach specially when you want to upload file with other model data.
Files selected on the client can not be submitted as JSON to the server. So we need to submit the form as a Collection to the server. We also can not use applicationjson
as content-type.
Consider following example. The example is demonstrated with ASP.NET MVC application example.
First thing you need to do is add the File object as part of the model class.
public class ClientDocument
{
public int Id {get;set;}
public int ClientId {get;set;}
public string Title {get;set;}
// Below property is used for getting file from client to the server.
public IFormFile File {get;set;}
}
Then you need to create a form in the View. Assume that the view has Model type set to the above class.
<form id="someForm" method="post">
@Html.HiddenFor(m => m.ClientId)
<table>
<tr>
<td>
@Html.LabelFor(m => m.Title)
</td>
<td>
@Html.TextFor(m => m.Title)
</td>
</tr>
<tr>
<td>
@Html.LabelFor(m => m.File)
</td>
<td>
//Following line of code will render file control, where user can select file from the local machine.
@Html.TextBoxFor(m => m.File, new { Type = "file" })
</td>
</tr>
<tr>
<td colspan="2">
<button type="button" onclick="SubmitForm();">Submit</button>
</td>
</tr>
</table>
</form>
Following is the JavaScript code for submitting the form. SubmitForm function in the JavaScript will convert the form to a FormData object.
FormData is a JavaScript object which represents data as a colleciton of Key/value pairs. Once the FormData object is created, we will post it to the server. As I mentioned above we can not use applicationjson
content-type, we need to use multipart/form-data
as encodingtype of the payload.
<script>
function SubmitForm() {
if ($("#someForm").valid()) {
var form = $("#someForm")[0];
var data = new FormData(form);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "http://www.somedomain.com/api/ClientDocument/Save",
data: data,
processData: false,
contentType: false,
cache: false,
beforeSend: function () {
// show waiting icon.
},
success: function (data) {
//Hiding waiting icon;
//Display the response in the UI.
},
error: function (xhr, status, errorThrown) {
console.log('ERROR : ' + xhr.responseText);
}
});
}
}
</script>
Now at the server end the controller action would look like following.
public IActionResult Save(ClientDocument model)
{
try
{
//Access File Property to save it on server or upload to some storage
var fileObject = model.File;
var tartgetLocation = "D:\ClientDocuments\" + fileObject.FileName;
using (var stream = new FileStream(tartgetLocation , FileMode.Create))
{
fileObject.CopyTo(stream);
}
// Write code to save information to database.
}
catch (Exception ex)
{
//Handle Exception
return Json(new {Status= "Failed"});
}
return Json( new {Status= "Success"});
}
I know that this is not the exact answer you might be looking for. But this should give you an idea about how to approach the problem and apply the same technique if applicable in your use case.