I'm looking to send the following fields to a MVC action
public class AddProductViewModel
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
public bool Enabled { get; set; }
public List<CategorySelectModel> Categories { get; set; } = new List<CategorySelectModel>();
public List<IFormFile> Photos { get; set; } = new List<IFormFile>();
}
CategorySelectModel:
public string CategoryId { get; set; }
public string CategoryName { get; set; }
and I haved used what i believe represents the actual json data...but I dont get why it isnt posting the data to the action
here is the js code where I have serialized the data and send to the controller
function SubmitProducts(element)
{
element.preventDefault();
let ulContainer = document.getElementById("dropDownAndSel").getElementsByTagName('ul')[0];
var Categories = [];
let x = document.getElementById("dropDownCategories");
for (let i = 0; i < x.children.length; i++) {
if (x.options[i].selected) {
let CategoryName = x.options[i].innerHTML;
let CategoryId = x.children[i].value;
let dropdownItems = { CategoryId, CategoryName };
if (!Categories.includes(dropdownItems)) {
Categories.push(dropdownItems);
}
}
}
let pId = document.getElementById('pId').value;
let ProductId = pId;
let ProductName = document.getElementById('ProductName').value;
if (!ProductName || ProductName.length ==0) {
alert('ProdutName cannot be null or empty');
return;
}
let priceStr = document.getElementById('productPriceId').value;
if (!priceStr || priceStr.length == 0) {
alert('Price cant be empty')
return;
}
let Price = parseFloat(priceStr);
let QuantityStr = document.getElementById('qtyNum').value;
if (!QuantityStr || QuantityStr.length==0) {
alert('Quantity cant be empty');
return;
}
let Quantity = parseInt(QuantityStr);
var formData = new FormData();
let filesContainer = document.getElementById('photoProduct_0');
for (let i = 0; i < filesContainer.files.length; i++) {
formData.append('model.Photos', filesContainer.files[i], filesContainer.files[i].name);
}
formData.set('model.ProductId', ProductId);
formData.set('model.ProductName', ProductName);
formData.set('model.Price', Price);
formData.set('model.Quantity', Quantity);
formData.set('model.Categories', JSON.stringify(Categories));
$.ajax({
url: '/' + 'Product' + '/' + 'AddProduct',
type: 'POST',
contentType: false,
processData: false,
data: formData,
success: console.log('success'),
});
}
Here is the action signature:
[HttpPost]
public async Task<IActionResult> AddProduct([FromBody] AddProductViewModel model)
Code above post FormData data. Therefore, the AddProductViewModel parameter should be bound using form-data in the request body:
[HttpPost]
public async Task<IActionResult> AddProduct([FromForm] AddProductViewModel model)
Reference to the following post: ASP.NET Core form POST results in a HTTP 415 Unsupported Media Type response
Related
My ajax POST request does'nt seem to be hitting my contoller, although i have used other Ajax post requests in my application this one doesnt seem to be working. My first throught was the datatypes within the model were not strings but other than that i can't seem to figure out why it isnt working.
Model
public class AppointmentViewModel
{
public List<DTO.Appointment> appointments { get; set; }
public DTO.Appointment appointment { get; set; }
public int AppointmentId_Input { get; set; }
public string AppointmentTitle_Input { get; set; }
public string AppointmentName_Input { get; set; }
public DateTime AppointmentStartTime_Input { get; set; }
public DateTime AppointmentEndTime_Input { get; set; }
public int AppointmentType_Input { get; set; }
public List<DTO.AppointmentType> appointmentTypes { get; set; }
}
Controller:
public ActionResult AddAppointment(Models.AppointmentViewModel avm)
{
BLL.FTSPManager fm = new BLL.FTSPManager();
DTO.Appointment a = new DTO.Appointment()
{
Id = avm.AppointmentId_Input,
Info = avm.AppointmentTitle_Input,
Name = avm.AppointmentName_Input,
StartTime = avm.AppointmentStartTime_Input,
EndTime = avm.AppointmentEndTime_Input,
type = new DTO.AppointmentType()
{
Id = avm.AppointmentType_Input
}
};
return Json(avm);
}
Ajax Request:
$('#btnAdd').click(function () {
var id, title, name, startTime, endTime, AppointmentType
id = $('#hdnAppointmentId').val();
title = $('#txtTitle').val();
name = $('#txtName').val();
startTime = $('#txtStartDate').val();
endTime = $('#txtEndDate').val();
AppointmentType = $('#drptype').val();
var JsonData = {
AppointmentId_Input: id,
AppointmentTitle_Input: title,
AppointmentName_Input: name,
AppointmentStartTime_Input: startTime,
AppointmentEndTime_Input: endTime,
AppointmentType_Input: AppointmentType
};
$.ajax({
type: "POST",
url: '#Url.Action("AddAppointment", "Admin")',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(JsonData),
dataType: "json",
success: function (data) {
return false;
}
});
})
You can use a FormData function. I can give for you a working example:
Html code(button, without other "input" tags:
<div class="form-group">
<button type="button" id="dataSend">DataSend</button>
</div>
Javascript code:
$("#dataSend").on('click', function () {
var formData = new FormData();
formData.append('Image', $('#file')[0].files[0]);
formData.append('Title', document.getElementById('Title').value);
formData.append('Description', document.getElementById('Description').value);
formData.append('Topic', document.getElementById('Topic').value);
formData.append('AdditionalFields', JSON.stringify(obsFields));
$.ajax({
contentType: false,
processData: false,
type: 'POST',
url: '/Collection/Create',
data: formData,
success: function () {
console.log("success.");
},
error: function () {
console.log("error.");
},
});});
C# code(controller):
[HttpPost]
public async Task<IActionResult> Create(DataForm AllData)
{
return RedirectToAction("Action-method", "Controller");
}
C# code(model):
public class DataForm
{
public string Title { get; set; }
public string Description { get; set; }
[EnumDataType(typeof(Topic))]
public Topic? Topic { get; set; }
public IFormFile Image { get; set; }
public string AdditionalFields { get; set; }
}
Field "AdditionalFields" is a son converted and in Controller it deserialized to 'List list'.
I'm waiting for your questions.
I am trying to call the controller from ajax and sending model data which consist some list of data inside it. I am getting the count correct for them but inside the list properties are coming null.
Controller:
public JsonResult InsertorUpdate(IncidentEdit incident)
{
try
{
SrvincidentDtls.TicketNo = incident.TicketNo;
SrvincidentDtls.Priority = incident.Priority;
SrvincidentDtls.Status = incident.Status;
SrvincidentDtls.Title = incident.Title;
SrvincidentDtls.IsActive = incident.IsActive;
List<Comments> lstComm = new List<Comments>();
if(incident.CommentList!=null )
{
foreach (var comm in incident.CommentList)
{
Comments Comm = new Comments();
Comm.Comment = comm.Comments;
Comm.AddedBy = comm.AddedBy;
Comm.AddedBy_ID = comm.AddedBy_ID;
Comm.CreatedDate = comm.CreatedDate;
lstComm.Add(Comm);
}
}
SrvincidentDtls.Comments = lstComm.ToArray();
SrvincidentDtls.Description = incident.Description;
var result=proxyService.InsertorUpdateIncidentDetails(SrvincidentDtls);
return Json(new { success = true, jvalue = result }, JsonRequestBehavior.AllowGet);
}
catch(Exception ex)
{
throw ex;
}
}
Model:
public class IncidentEdit
{
public string Title { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public string Status { get; set; }
public string Priority { get; set; }
public List<IncidentComments> CommentList { get; set; }
}
Generic Class:
public class IncidentComments
{
public string Comments { get; set; }
public string AddedBy { get; set; }
public string AddedBy_ID { get; set; }
public DateTime CreatedDate { get; set; }
}
Ajax call:
function InsertOrUpdate(){
incidentDetails = {
Title: $("#txtTitle").val(),
Description: $("#txtDescription").val(),
Priority: $('#selPriority option:selected').val(),
Status: $('#selStatus option:selected').val(),
IsActive: 1,
CreatedDate :$('#spncrtdDt').text(),
CommentList:PopulateCommentList()
};
$.ajax({
type: "Get", //HTTP POST Method
url: insertORupdatUrl, // Controller/View
data: {incident:incidentDetails},
contentType: "application/json; charset=utf-8",
success: function (data) {
}
});
}
js function:
function PopulateCommentList() {
var CommentList = [];
var dtTable = $('#dvCommentTbl').DataTable();
for (var i = 0; i < 10; i++) {
if (dtTable.row(i).data() != "" && dtTable.row(i).data() != null && dtTable.row(i).data() != undefined) {
CommentList.push({
Comments: dtTable.row(i).data()[1],
AddedBy: dtTable.row(i).data()[2],
AddedBy_ID: dtTable.row(i).data()[0],
CreatedDate: dtTable.row(i).data()[3]
});
}
}
return CommentList;
}
the count for comment list is coming fine but the data like Added_By,comments,Created Dtae all coming null.
Plz help.
You can take a variable like
var commlist=PopulateCommentList();
then populate it in your model json:
incidentDetails = {
Title: $("#txtTitle").val(),
Description: $("#txtDescription").val(),
Priority: $('#selPriority option:selected').val(),
Status: $('#selStatus option:selected').val(),
IsActive: 1,
CreatedDate :$('#spncrtdDt').text(),
CommentList:commlist
};
it will work as it work for me.
So when I set the javascript ReminderModel object properties this will work and my controller will receive the object if I set LeadId and StaffId to 1, but as soon as I turn them into strings the controller receives a null object.
I'm not sure what's going on, it might be a problem with the quotes?
My view code
var ReminderModel = {
"LeadId": "#Model.Id",
"StaffId": "1a53c286-b17e-4afd-9ccb-684fd1a92f7b",
"Subject": "Call Back",
"Time": "iTime",
"Date": "iDate"
};
$.ajax({
url: "#Url.Action("SetReminder","Appointment")",
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(ReminderModel),
success: function (valid) {
if (valid) {
//show that id is valid
} else {
//show that id is not valid
}
}
});
My controller Method
[HttpPost]
public async Task<ActionResult> SetReminder([FromBody] ReminderViewModel viewModel)
{
using (var db = new LeadCoreDbContext())
{
DateTime dt = DateTime.MinValue;
DateTime.TryParse($"{viewModel.Date} {viewModel.Time}", out dt);
if (dt == DateTime.MinValue)
throw new Exception("Failed to set reminder");
var reminder = new Reminder
{
Deleted = false,
LeadId = viewModel.LeadId,
Subject = viewModel.Subject,
TimeToRemind = dt,
StaffId = viewModel.StaffId
};
db.Reminder.Add(reminder);
await db.SaveChangesAsync();
}
return Content("received");
}
Here is the model
public class ReminderViewModel
{
public int Id { get; set; }
public int LeadId { get; set; }
public int StaffId { get; set; }
public string Date { get; set; }
public string Time { get; set; }
public string Subject { get; set; }
}
I am running into a problem. I have my database properly configured and image is saving in database properly but dont know how to construct url for the image saved in database as i have to supply it to the knockout view model for binding.
public JsonResult GetPosts()
{
var ret = (from post in db.Posts.ToList()
orderby post.PostedDate descending
select new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = post.ApplicationUser.UserName,
// having problem at this line dont know how to construct url at this line as i have to supply url
// (String type to the PostedByAvatar)
PostedByAvatar = db.Files.SingleOrDefault(s => s.ApplicationUserId == post.PostedBy),
PostedDate = post.PostedDate,
PostId = post.PostId,
}).AsEnumerable();
return Json(ret, JsonRequestBehavior.AllowGet);
}
this is the knockout function--------
function Post(data) {
var self = this;
data = data || {};
self.PostId = data.PostId;
self.Message = ko.observable(data.Message || "");
self.PostedBy = data.PostedBy || "";
self.PostedByName = data.PostedByName || "";
self.PostedDate = getTimeAgo(data.PostedDate);
self.PostedByAvatar = data.PostedByAvatar || "";
self.error = ko.observable();
self.PostComments = ko.observableArray();
and this is the view model to get the existing post, comment etc with image from the database-----
function viewModel() {
var self = this;
self.posts = ko.observableArray();
self.newMessage = ko.observable();
self.error = ko.observable();
self.loadPosts = function () {
// to load existing posts
$.ajax({
url: postApiUrl1,
datatype: "json",
contentType: "application/json",
cache: false,
type: 'Get'
})
and on my view page, this the container box to load the image with post-----
<ul id="msgHolder" data-bind="foreach: posts">
<li class="postHolder">
<img data-bind="attr: { src: PostedByAvatar }">
<p><a data-bind="text: PostedByName"></a>: <span data-bind=" html: Message"></span></p>
Now, the model class which saves the image in database is something like this.It has ApplicationUserId as foreign key pointing to ApplicationUserClass---
public class File
{
[Key]
public int FileId { get; set; }
[StringLength(255)]
public string FileName { get; set; }
[StringLength(100)]
public string ContentType { get; set; }
public byte[] Content { get; set; }
public FileType FileType { get; set; }
public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
and ApplicationUserClass is something like this---
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationUser()
{
this.Posts = new HashSet<Post>();
this.Files = new HashSet<File>();
}
public virtual ICollection<File> Files { get; set; }
public virtual ICollection<Post> Posts { get; set; }
This is the image saved in database.Now, i want to know how to construct url for the image saved in the database as i have to supply it to the view model in string form. or there is any approach better than this.
This is my Post class which have many to one relationship with ApplicationUser class and foreign key is PostedBy pointing the ApplicationUser Class----
public class Post
{
public Post()
{
this.PostComments = new HashSet<PostComment>();
}
[Key]
public int PostId { get; set; }
public string Message { get; set; }
public int? PostedBy { get; set; }
public System.DateTime PostedDate { get; set; }
public virtual ICollection<PostComment> PostComments { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
Although it is possible to pass a Base64 string as the src of the <img>, I think the most sensible way would be to not return the actual bytes from the Ajax call but rather create a url that will request the image bytes from the server.
First, add the required Action that will serve the image data:
[HttpGet]
public FileResult GetFileData(int fileId)
{
var file = db.Files.Single(x => x.FileId == fileId);
return File(file.Content, file.ContentType);
}
Now, change your GetPosts action to return url in the PostedByAvatar property:
public JsonResult GetPosts()
{
var ret = (from post in db.Posts.ToList()
orderby post.PostedDate descending)
select new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = post.ApplicationUser.UserName,
PostedByAvatar = _GenerateAvatarUrlForUser(post.PostedBy),
PostedDate = post.PostedDate,
PostId = post.PostId,
});
return Json(ret, JsonRequestBehavior.AllowGet);
}
private string _GenerateAvatarUrlForUser(int? userId)
{
if (!user.HasValue)
return null;
var avatarImage = db.Files.SingleOrDefault(s => s.ApplicationUserId == userId);
if (avatarImage != null)
return Url.Action("GetFileData", new { fileId = avatarImage.FileId });
return null;
}
I'm looking to bind a JSON object to a List nested in an object.
Background
I have a Category class that contains a list of ConfigurationFunds:
public class Category
{
public int Id { get; set; }
public string CountryId { get; set; }
public string Name { get; set; }
public List<ConfigurationFund> Funds { get; set; }
public Category()
{
Funds = new List<ConfigurationFund>();
}
}
public class ConfigurationFund
{
public int Id { get; set; }
public string CountryId { get; set; }
public string Name { get; set; }
public ConfigurationFund()
{
}
}
The user can select a number of Funds per Category, and then I want to POST a JSON string back to my Controller and have the ModelBinder bind the JSON to the object model.
This is my Action method:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Category category)
{
// Categoy.Id & Categoy.CountryID is populated, but not Funds is null
return Json(true); //
}
So far, I have this jQuery:
$('#Save').click(function (e) {
e.preventDefault();
var data = {};
data["category.Id"] = $('#CategorySelector').find(":selected").val();
data["category.countryId"] = $('#CategorySelector').find(":selected").attr("countryId");
var funds = {};
$('#ConfiguredFunds option').each(function (i) {
funds["funds[" + i + "].Id"] = $(this).val();
funds["funds[" + i + "].countryId"] = $(this).attr("countryId");
});
data["category.funds"] = funds;
$.post($(this).attr("action"), data, function (result) {
// do stuff with response
}, "json");
});
But this isn't working. The properties of Category are populated, but the List<ConfigurationFund>() isn't being populated.
Question
How do I need to modify this to get it to work?
Supplementary Info
Just to note, I've also tried to post the Category & ConfiguredFunds separately, and it works, with something similar to the following:
$('#Save').click(function (e) {
e.preventDefault();
var data = {};
data["category.Id"] = $('#CategorySelector').find(":selected").val();
data["category.countryId"] = $('#CategorySelector').find(":selected").attr("countryId");
$('#ConfiguredFunds option').each(function (i) {
data["configuredFunds[" + i + "].Id"] = $(this).val();
data["configuredFunds[" + i + "].countryId"] = $(this).attr("countryId");
});
$.post($(this).attr("action"), data, function (result) {
// do stuff with response
}, "json");
});
In the following Action method, the ConfiguredFunds are populated, and the Category is also populated. However, the Category's List isn't populated. I need the Category & its List to be populated.
public ActionResult Edit(List<ConfigurationFund> configuredFunds, Category category)
{
return Json(true);
}
I've figured it out. I just needed to change
data["category.Id"] = $('#CategorySelector').find(":selected").val();
data["category.countryId"] = $('#CategorySelector').find(":selected").attr("countryId");
var funds = {};
$('#ConfiguredFunds option').each(function (i) {
funds["funds[" + i + "].Id"] = $(this).val();
funds["funds[" + i + "].countryId"] = $(this).attr("countryId");
});
data["category.funds"] = funds;
$.post($(this).attr("action"), data, function (result) {
// do stuff with response
}, "json");
to:
data["category.Id"] = $('#CategorySelector').find(":selected").val();
data["category.countryId"] = $('#CategorySelector').find(":selected").attr("countryId");
$('#ConfiguredFunds option').each(function (i) {
data["category.funds[" + i + "].Id"] = $(this).val();
data["category.funds[" + i + "].countryId"] = $(this).attr("countryId");
});
$.post($(this).attr("action"), data, function (result) {
// do stuff with response
}, "json");
Basically, I just specified that the funds belong to a Category with data["category.funds"]