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);
}
Related
I created a form. I am sending the data in this form as JSON.
If I just submit the formData (I also change the controller to [FromBody] Image request) and set the contentType and processData to false, the formData is not null.
I think "document" returns null because I am sending the data as JSON. How can I solve this issue I'm stuck in this issue.
Ajax Request
let myProfile = {
id: 0,
title: "",
text: "",
document: File,
};
myProfile.title = "Lorem ipsum";
myProfile.text = "Lorem ipsum";
var formData = new FormData();
formData.append('file', $('#file').get(0).files[0]);
formData.append('fileName', $("#fileName").val());
var myFile = formData.get('file');
myProfile.document = myFile;
$.ajax({
url: `/admin/myprofile`,
type: "POST",
data: JSON.stringify(myProfile),
contentType: "application/json",
dataType: 'json',
success: ....
Cshtml
<div class="form-group">
<input type="file" name="document" asp-for="document" id="file" />
</div>
Controller
[HttpPost("myprofile")]
public IActionResult MyProfile([FromBody] MyProfileDTO request)
{
return ...
}
Class
public class Image
{
public IFormFile file { get; set; }
public string fileName { get; set; }
}
public class MyProfileDTO
{
public string Title { get; set; }
public string Text { get; set; }
public Image Document{ get; set; }
}
Ajax Request
let myProfile = {
id: 0,
title: "",
text: "",
document: File,
};
myProfile.title = "Lorem ipsum";
myProfile.text = "Lorem ipsum";
var formData = new FormData();
formData.append('file', $('#file').get(0).files[0]);
formData.append('title', myProfile.title);
formData.append('text', myProfile.text);
$.ajax({
url: `/admin/myprofile`,
type: "POST",
data: formData ,
contentType: "application/json",
success: ....
Controller
[HttpPost("myprofile")]
public IActionResult MyProfile([FromBody] MyProfileDTO request, IFormFile file)
{
return ...
}
Class
public class MyProfileDTO
{
public string Title { get; set; }
public string Text { get; set; }
}
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
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
});
I have a Model as below:
public class Class1
{
public int Id { get; set; }
public DateTime Start { get; set; }
}
and I have an ActionResult which is like this:
public ActionResult Create(Class1 model)
{
...
}
now, I want to fill Start property from another external javascript file using ajax like this:
$.ajax({
url: "/Admin/Create",
dataType: "Json",
type: "Post",
data: Start:"..."
});
How can I access to another View TextBox and fill that using ajax? What should I do in data on ajax?
Please try below code:-
var model = { Name :"Shyju",
Location:"Detroit",
Interests : ["Code","Coffee","Stackoverflow"]
};
$.ajax({
type: "POST",
data: JSON.stringify(model),
url: url,
contentType: "application/json"
}).done(function (res) {
$("#SomeDivToShowTheResult").html(res);
});
public class DashboardViewModel
{
public string Name {set;get;}
public string Location {set;get;}
public List<string> Interests {set;get;}
}
[HttpPost]
public PartialViewResult IndexPartial([FromBody] DashboardViewModel m)
{
return PartialView("_IndexPartial",m);
}
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>