Unable to send Form Data & File Upload via AJAX to controller - javascript

I am trying to send a bunch of form data from my view and map it to a ViewModel parameter in my controller. In addition, I am trying to send a file with this request which will map to a separate parameter.
When formData is sent through to the controller, it correctly maps the file upload to the file parameter, however, the model parameter properties are all null/defaults.
In summary, my question is this: how do I map my form element values to to MyViewModel paramter in my controller whilst sending a file too?
Model:
public class MyViewModel
{
public int AsssumptionSetId { get; set; }
public int BuildingBlockId { get; set; }
public string ReplacementCode { get; set; }
public decimal Rounding { get; set; }
public string DataSource { get; set; }
public bool AER { get; set; }
public int Term { get; set; }
}
View:
This view is strongly typed to the MyViewModel:
<form id="buildingBlockForm">
#Html.HiddenFor(model => model.AsssumptionSetId)
#Html.HiddenFor(model => model.BuildingBlockId)
#Html.TextBoxFor(m => m.ReplacementCode)
#Html.TextBoxFor(m => m.Rounding)
#Html.DropDownListFor(m => m.DataSource, (SelectList)ViewBag.DataSources)
#Html.DropDownListFor(m => m.Term, (SelectList)ViewBag.Terms)
#Html.CheckBoxFor(m => m.AER)
<input type="file" id="file" name="file" />
<input class="button green-button" type="submit" value="Create" />
</form>
Controller:
public ActionResult CreateBuildingBlock(MyViewModel model, HttpPostedFileBase file)
{
// all of the 'model' properties = null instead of the form values
// file = the file I chose to upload and works as expected
}
JS:
var formData = new FormData($('#buildingBlockForm'));
// Get file and append to form data (Should only be 1)
$.each(Files["csv"], function (key, value) {
formData .append("file", value);
});
// Send file
$.ajax({
url: '/Assumptions/CreateBuildingBlock',
type: 'POST',
data: formData,
cache: false,
dataType: "json",
contentType: false,
processData: false,
success: function (response) {
// Handle success
},
error: function (xhr, status, errorThrown) {
// Handle errors
}
});

Turns out I was missing an index when grabbing the form that needs serializing.
new FormData($('#buildingBlockForm')[0]);
This solved my issue.

since your form contains a file-input type, you need your form to handle this submission (enctype).
<form id="buildingBlockForm" enctype="multipart/form-data">
Also, if you want to stick with MVC's form helper, it would alleviate the issues you may have with a script-based ajax post.
#using (Ajax.BeginForm("CreateBuildingBlock", "Assumptions", null, new AjaxOptions { HttpMethod = "POST", OnSuccess = "postSuccess", OnFailure = "postFailed" }, new { enctype = "multipart/form-data" }))
{
// your form fields here
}
<script>
function postSuccess() {
// handle success here
}
function postfailed() {
// handle failed post here
}
</script>

Related

ASP Net Core3.1 AJAX Post Sending NULL to Controller

It has been 3 days am trying to sending the [POST] form data using ajax, Javascript & HTML into MVC controller but getting null.
Please find the controller and ajax code please help me on this also let me know is it possible or not to send the data from ajax to mvc controller?
I am beginner .....thanks in advance.
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> CreateNewBug([FromBody] BugTrackerRequest bugTrackerRequest)
{
// BugTrackerResponse bugTrackerResponse = null;
if (ModelState.IsValid)
{
var Request = await _projectDetails.CreateNewBug(bugTrackerRequest);
if (Request > 0)
{
BugTrackerResponse bugTrackerResponse = new BugTrackerResponse();
bugTrackerResponse.Issuccess = true;
// return Ok(new {Messgage="Data save successfully in the DB"});
return Ok();
}
}
return StatusCode(500, new { Message = "Something went wrong" });
// return bugTrackerResponse;
//return StatusCode();
}
public class BugTrackerRequest:APIResponse
{
public int TicketId { get; set; }
public string ProjectName { get; set; }
public string ProjectDescription { get; set; }
public string Title { get; set; }
public string Status { get; set; }
public string AssignTo { get; set; }
public string AssignFrom { get; set; }
public byte[] Attachment { get; set; }
public string Impact { get; set; }
public string Platform { get; set; }
public string Priority { get; set; }
public string BugType { get; set; }
public DateTime CreatedDate { get; set; }
}
}
function savedetails() {
let saveuidetails = new BugdetailRequestclass();
saveuidetails.ProjectName = $('#projectprojectname').val();
saveuidetails.ProjectDescription = $('#description').val();
saveuidetails.Title = $('#title').val();
saveuidetails.Status = $('#status').val();
saveuidetails.AssignTo = $('#assignto').val();
saveuidetails.AssignFrom = $('#assignfrom').val();
saveuidetails.Attachment = $('#Attfileupload').val;
saveuidetails.Impact = $('#Priority').val();
saveuidetails.Platform = $('#platform').val();
saveuidetails.Priority = $('#Priority').val();
saveuidetails.BugType = $('bugtype').val();
saveuidetails.CreatedDate = $('#currentdate').val();
$.ajax({
type: 'POST',
url: '/TicketController1/CreateNewBugFromBody',
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(saveuidetails),
success: function (data) {
console.log('success', data);
},
error: function () { alert('Exeption:'); }
});
}
Your URL in POST is wrong, please change
/TicketController1/CreateNewBugFromBody
to
/TicketController1/CreateNewBug
Please verify that your controller class is named TicketController1.
To start with, please comment out
saveuidetails.Attachment = $('#Attfileupload').val;
in js and
public DateTime CreatedDate { get; set; }
public byte[] Attachment { get; set; }
When controller method is working, you may look at the Attachment which will be a challenge.
You basically have three choices (https://stackoverflow.com/a/4083908/14072498):
Base64 encode the file, at the expense of increasing the data size by
around 33%, and add processing overhead in both the server and the client
for encoding/decoding.
Send the file first in a multipart/form-data POST, and return an ID to the
client. The client then sends the metadata with the ID, and the server re-
associates the file and the metadata.
Send the metadata first, and return an ID to the client. The
client then sends the file with the ID, and the server re-associates the
file and the metadata.
Else, your code shown here looks OK to me, and there is no problem using a MVC controller for this. If controller contains API methods only, you should extend from ControllerBase instead of Controller, and annotate controller with [ApiController]. The latter invokes model validation automatically.
When implementing new API end-points, always start with something simple and verify with e.g. Postman that you can reach your new end-point.
url: '/TicketController1/CreateNewBugFromBody',
public async Task<IActionResult> CreateNewBug([FromBody] BugTrackerRequest bugTrackerRequest)
First, check your request URL and the action method, it seems that you are submitting the form to the CreateNewBugFromBody method, instead of CreateNewBug action method. So try to change your code as below (I assume your controller name is TicketController1 and you want to submit to the CreateNewBug method):
$.ajax({
type: 'POST',
url: '/TicketController1/CreateNewBug',
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(saveuidetails),
success: function (data) {
console.log('success', data);
},
error: function () { alert('Exeption:'); }
});
Second, please check your JQuery object BugdetailRequestclass, in the action method, it receives a BugTrackerRequest object. So, try to modify your code as below (please change the request url and the jquery selector value to yours):
function savedetails() {
var saveuidetails = {}; //define a object
saveuidetails.ProjectName = $('#ProjectName').val();
saveuidetails.ProjectDescription = $('#Description').val();
saveuidetails.Title = $('#Title').val();
saveuidetails.Status = $('#Status').val();
saveuidetails.AssignTo = $('#AssignTo').val();
saveuidetails.AssignFrom = $('#AssignFrom').val();
saveuidetails.Attachment = $('#Attfileupload').val;
saveuidetails.Impact = $('#Priority').val();
saveuidetails.Platform = $('#Platform').val();
saveuidetails.Priority = $('#Priority').val();
saveuidetails.BugType = $('#BugType').val();
saveuidetails.CreatedDate = $('#CreatedDate').val();
$.ajax({
type: 'POST',
url: '/Home/CreateNewBug',
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(saveuidetails),
success: function (data) {
console.log('success', data);
},
error: function () { alert('Exeption:'); }
});
}
Besides, you could add a breakpoint in the JavaScript resource and CreateNewBug action method, and check whether you could get the correct data before/after send Ajax request.
Screenshot as below:
JavaScript debug screenshot (using F12 developer tools)
Action method debug screenshot:

How to bind JavaScript array of JSON objects to a List of objects in viewModel. dotnetcore mvc

This is my javascript array of json objects
var pObjIds = [{"Id":"2","Name":"small"},{"Id":"3","Name":"average"}]
I have collected my form fields into a FormData() like this
var form = new FormData($(this)[0]);
I have appended the array of json objects to the FormData like this
form.append("Availability", pObjIds);
I have a ViewModel with a property
public List<Item> Availability { get; set; }
The Item class looks like this
public class Item
{
[JsonProperty(PropertyName = "Id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
}
My controller method to receive the form data is
[HttpPost]
public IActionResult AddSupplier(SupplierVM vm, List<Item> list)
{
if (ModelState.IsValid)
{
}
return View("AddSupplier", vm);
}
My intention is to bind the appended Availability in the formData to the property
public List<Item> Availability { get; set; } in the ViewModel.
The above code is what I have tried but its not binding. Always returning count=0 for Availability.
Are my doing something wrong or is there a better way i can do it?
I have used FormCollection in controller but still not seen the appended array of json objects but i can log it in the console and see that it is appended successfully.
I am using dotnet core 3.0 mvc.
Thanks in advance.
This is the client side code that calls the AddSupplier
var form = new FormData($(this)[0]);
form.append("Availability", pObjIds);
$.ajax({
type: 'POST',
url: '/supplier/addsupplier/',
data: form,
processData: false,
contentType: false,
datatype: 'json',
success: function (result) {
if (result.status == false) {
swal({
title: 'Error!',
text: result.msg,
icon: "error",
button: "Ok",
});
}
},
error: function () {
swal({
title: "Unknown Error!",
text: "unable to process request!",
icon: "error",
button: "Ok",
});
}
});
I have a ViewModel with a property
public List<Item> Availability { get; set; }
My intention is to bind the appended Availability in the formData to the property public List<Item> Availability { get; set; } in the ViewModel.
To achieve your requirement, you can try to append values for FormData object like below.
var form = new FormData($(this)[0]);
//form.append("Availability", pObjIds);
$(pObjIds).each(function (index, el) {
form.append(`Availability[${index}].Id`, el.Id);
form.append(`Availability[${index}].Name`, el.Name);
});
$.ajax({
type: 'POST',
url: '/supplier/addsupplier/',
data: form,
processData: false,
contentType: false,
datatype: 'json',
success: function (result) {
// code logic here
//...
In controller action AddSupplier
[HttpPost]
public IActionResult AddSupplier(SupplierVM vm)
{
//code logic here
View model class SupplierVM
public class SupplierVM
{
public int Id { get; set; }
//other properties
public List<Item> Availability { get; set; }
}
Test Result

ASP.NET: POST List<Object> / Model with Ajax (JSON) from view to controller

Working in ASP.NET Core where I'm trying to POST a List of Items through Ajax. Ideally, I would like to pass the entire ReportViewModel but I haven't been able to match the signature correctly (since passing a DateTime or a List isn't that easy).
My question
How to POST a List<Object> from the view with Ajax to the controller?
OR How to POST a Model from the view with Ajax to the controller?
I currently have the following code:
Models
public class ReportViewModel {
public int ReportType { get; set; };
public DateTime DateFrom { get; set; };
public DateTime DateTo { get; set; };
public List<Item> ItemList{ get; set; };
}
public class Item {
// Properties are simple types
}
View (ReportView)
#model Namespace.ViewModels.ReportViewModel
#inject Namespace.Resource Resources
<!-- HTML code -->
<form>
<button class="ui button" type="submit" onclick="return createPDF();">#Resources.Save</button>
</form>
<script>
function createPDF() {
alertify.set('notifier', 'position', 'bottom-left');
$.ajax({
type: "POST",
url: "CreatePDF",
data: JSON.stringify({
reportType: #Model.ReportType,
ticksDateFrom: #Model.DateFrom.Ticks,
ticksDateTo: #Model.DateTo.Ticks
#* TODO: Add the List<Items> itemList (from #Model.ItemList)*#
}),
contentType: 'application/json',
// Code for success and error
});
return false;
};
</script>
Controller (ReportController)
[HttpPost]
public JsonResult CreatePDF([FromBody] dynamic data) {
// Lots of code
return Json(new { isError = false });
}
/* When passing the entire model
* [HttpPost]
* public JsonResult CreatePDF([FromBody] ReportViewModel model) {
* // Lots of code
* return Json(new { isError = false });
* }
*/
I tried passing the model as seen below but that leaves me with the parameter in the controller being null or as a new "empty" object, depending if I use [FromBody] or not.
$.ajax({
type: "POST",
url: "CreatePDF",
data: #Html.Raw(Json.Serialize(Model)),
contentType: 'application/json',
// Code for success and error
});
You can use the BeginForm in your view that posts to a controller:
#model Namespace.ViewModels.ReportViewModel
#inject Namespace.Resource Resources
#using (Html.BeginForm("CreatePDF", "[PDFControllerName]", FormMethod.Post, new { #id = "pdfCreatorForm" }))
{
<!-- Send parameters to a controller like this (invisibly) -->
#Html.HiddenFor(m => m.ReportType)
#Html.HiddenFor(m => m.DateFrom.Ticks)
#Html.HiddenFor(m => m.DateTo.Ticks)
#Html.HiddenFor(m => m.ItemList) <!-- Send the List<Items> -->
<button type="submit" class="ui button" onclick="alertify.set('notifier', 'position', 'bottom-left')">#Resources.Save</button>
}
And then you don't need the JavaScript any more, another thing to keep in mind is to keep as much functionality on your server side as you can.
If you POST the form to a controller, you can access the view's parameters etc like this:
public JsonResult CreatePDF(ReportViewModel formData)
{
int reportType = formData.ReportType;
DateTime ticksDateFrom = formData.DateFrom.Ticks;
DateTime ticksDateTo = formData.DateTo.Ticks;
List<Items> itemList = formData.ItemList;
// Lots of code
}
And, you actually doesn't need to specify that it's taking in a HttpPost :)
I don't know what exactly I changed to make it work but the following compiles correctly. Could be the processData: true and cache: false properties?
Controller
[HttpPost]
public JsonResult CreatePDF([FromBody] ReportViewModel model)
{
// Lots of code
return Json(new { isError = false });
}
View (JS only)
$.ajax({
type: "POST",
url: "CreatePDF",
data: JSON.stringify(#Html.Raw(Json.Serialize(Model))),
contentType: 'application/json; charset=utf-8',
processData: true,
cache: false,
// Code for success and error
});

upload entire model to API via AJAX (mvc c#)

I am working with Ajax, mvc and c#, uploading my model to my api action, using this information I found here: stackoverflow: How to append whole set of model to formdata and obtain it in MVC.
This is my problem When following step by step the above link, my model in the api side comes null:
//this is the conten of the viewmodel object in the api action
guid:{00000000-0000-0000-0000-000000000000}
descripcion:null
Imagen:null
Title:null
This is my viewmodel
public class myViewModel
{
public Guid CursoId { get; set; }
[MaxLength(125)]
public string Titulo { get; set; }
public string Descripcion { get; set; }
[Required(ErrorMessage = "select image file for course")]
[DataType(DataType.Upload)]
public HttpPostedFileBase Imagen { get; set; } //note this is the image
}
My web api, it is a simple action to test
// POST: api/Test
[Route("test")]
public void Post([FromBody]myViewModel model)
{//do something
}
this is my view:
#model ajaxtest.ViewModel.myViewModel
<form id="Editcurso" method="post" action="#" enctype="multipart/form-data">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "Please fix the following errors.")
<div class="container">
<div class="form-group">
#Html.LabelFor(c => c.Titulo)
#Html.TextBoxFor(c => c.Titulo, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Titulo)
</div>
<div class="form-group">
#Html.LabelFor(c => c.Descripcion)
#Html.TextAreaFor(c => c.Descripcion, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Descripcion)
</div>
<div class="form-group">
#Html.LabelFor(m => m.Imagen)
#Html.TextBoxFor(m => m.Imagen, new { type = "file" })
#Html.ValidationMessageFor(m => m.Imagen)
</div>
<button id="submiter" type="submit" class="btn btn-primary">Listo!</button>
</div>
Here is my javascript:
$('#Editcurso').submit(function(e) {
e.preventDefault(); // prevent the default submit
if (!$(this).valid()) {
return; // exit the function and display the errors
}
jQuery.support.cors = true;
// Create a formdata to pass the model, since the view was generated from viewmodel, it should contain the model.
var model = new FormData($('#Editcurso').get(0));
$.ajax({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
url: '/api/test/test',
type: 'post',
dataType: 'json',
data: JSON.stringify(model),
processData: false,
contentType: false,
success: function (data) {
console.log(data);
return false;
},
error: function () {
alert('error al postear');
return false;
}
});
e.preventDefault(); // avoid to execute the actual submit of the form.
});
});
What do you think is wrong and how can I fix it? thanks.

HttpPostedfileBase is null using jQuery Ajax

I have problem with uploading file In Asp.net Mvc. First of all I should use Ajax to pass the upload file value.
In javascript I have model that I fill it, When I check it with debugger is correctly fill the object, but when I send this model to server (Controller )
The httpPostedfileBase value is Always null.
I search it on google, in some post I saw that I cant use file uploader with Ajax, but in other I saw that I can.
But I can not fix my Code.
There is my Javascript Code.
$(document).ready(function () {
$('#btnUploadFile').on('click', function () {
var data= new FormData();
debugger;
var files = $("#fileUpload").get(0).files;
if (files.length > 0) {
data.append("UploadedImage", files[0]);
}
var ResturantSharingViewModel =
{
Type: $("#SharingTargetType").val(),
SharingTitle: $("#SharingTitle").val(),
content: $("#Content").val(),
ItemId : $("#ItemId").val(),
Photos: files[0]
};
$.ajax({
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: '<%= Url.Action("SaveOneDatabase")%>',
data: JSON.stringify(ResturantSharingViewModel),
success: function (result) {
var rs = result;
},
error: function () {
alert("Error loading data! Please try again.");
}
});
My Controller public virtual bool SaveOneDatabase(ResturantSharingViewModel result)
My ResturantSharingViewModel View Model
public class ResturantSharingViewModel
{
public Guid SharingPremiumHistoryID { get; set; }
public string SharingTitle { get; set; }
public string Content { get; set; }
public DateTime AddedDate { get; set; }
public bool IsSubmit { get; set; }
public DateTime SubmitedDate { get; set; }
public IEnumerable<SelectListItem> SharingTypes { get; set; }
public IEnumerable<SelectListItem> SharingTargetType { get; set; }
public short Type { get; set; }
public Guid ItemId { get; set; }
public HttpPostedFileBase[] Photos { get; set; }
}
My Html Elements
<form enctype="multipart/form-data">
<article>
<%--<% =Html.BeginForm("Add","PremiumSharing") %>--%>
<hgroup class="radiogroup">
<h1>ارسال خبر</h1>
<%= Html.HiddenFor(model => model.SharingPremiumHistoryID) %>
<%= Html.HiddenFor(model => model.ItemId) %>
<div class="group">
<span> ارسال به </span>
<%= Html.DropDownListFor(model => model.SharingTargetType, Model.SharingTypes) %>
</div>
</hgroup>
<div class="newseditor">
<div class="input-form">
<%= Html.LabelFor(model => model.SharingTitle, "عنوان خبر") %>
<%= Html.TextBoxFor(model => model.SharingTitle) %>
</div>
<div class="input-form">
<%= Html.LabelFor(model => model.Content, "متن خبر") %>
<%= Html.TextAreaFor(model => model.Content) %>
</div>
<div><input id="fileUpload" type="file" />
</div>
<% if (ViewBag.IsInEditMode != null && !(bool)ViewBag.IsInEditMode)
{%>
<div class="input-form">
<%= Html.CheckBox("SendToInTheCity") %> ارسال در بخش «در شهر» فیدیلیو
</div>
<%} %>
<div class="input-submit">
<button name="post" id="btnUploadFile" onclick="uploadFile()" >ارسال خبر</button>
</div>
<br />
</div>
First, it's possible to upload with Ajax, the important thing is you need to set <form enctype="multipart/form-data"></form> on you form to tell it your form has an file upload input. Then you need to accept HttpPostedFileBase as an input parameter in your controller action.
Try this. Example of jquery upload code. (Taken mostly from How can I upload files asynchronously?)
function uploadFile(uploadId) {
var formData = new FormData($('form')[0]);
$.ajax({
url: '<%= Url.Action("SaveOneDatabase")%>',
type: 'Post',
beforeSend: function(){},
success: function(result){
},
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload) { // Check if upload property exists
// Progress code if you want
}
return myXhr;
},
error: function(){},
data: formData,
cache: false,
contentType: false,
processData: false
});
}
HTML Form needs this attribute. See this post why you need it -> What does enctype='multipart/form-data' mean?
enctype="multipart/form-data"
C#
[HttpPost]
public ActionResult SaveOneDatabase(HttpPostedFileBase file)
{
}
I have modified #a moradi's answer.
JS:
//FormData:
//Consider it a normal form but with "multipart/form-data" encoding type.
//Inside it works same as XMLHttpRequest.send() method.
var model = new FormData();
model.append("File", $('#file')[0].files[0]);
model.append("Name", "Name");
$.ajax({
url: someUrl,
type: "POST",
data: model,
//contentType:
//Sets the ContentType in header.
//The default contentType is "application/x-www-form-urlencoded; charset=UTF-8". But this will prevent us sending AntiForgeryToken to service/controller.
//To prevent this contentType is set to false.
contentType: false,
//processData:
//To prevent data getting converted to string format, 'processData' option is set to false.
processData: false,
success = function (m) {...}
error = function (m) {...}
});
View Model:
public class PhotoAlbumViewModel {
public string Name { get; set; }
public HttpPostedFileBase File { get; set; }
}
Controller:
public JsonResult AddPhoto(PhotoAlbumViewModel model) {
...
}
Refrence:
Reffer following links for details: FormData , JQuery , ContentType
View:
<script/>
var add_photo_url = "#Url.Action("AddPhoto", "Gallery")";
var model = new FormData();
var i=0;//selected file index
model.append("File", files[i]);
model.append("Name", "test");
$.ajax({// and other parameter is set here
url: add_photo_url,
type: "POST",
data: model,
dataType: "json",
cache: false,
contentType: false,
processData: false
})
.always(function (result) {
});
</script>
View Model:
public class PhotoAlbumViewModel {
public string Name { get; set; }
public HttpPostedFileBase File { get; set; }
}
Controller:
public JsonResult AddPhoto(PhotoAlbumViewModel model) {
// var result =...
// and set your result;
return Json(result, JsonRequestBehavior.AllowGet);
}

Categories

Resources