Passing objects from Ajax to C# WebApi - javascript

I’m still not fluent in calling WebAPI services. I succeed in simple items, but now my needs are getting complicated and things always fail.
I use MVC 5 for WebAPI, and call using regular jQuery functions.
My Model
Here I manage appointments of patients in a clinic. I use the following model for Patient and Appointment entities:
public class Patient
{
// Personal data
public int Id { get; set; }
public string Name { get; set; }
}
public class Appointment
{
public int Id { get; set; }
public DateTime Date { get; set; } // date only
public int Order { get; set; }
public string PatientName { get; set; }
// Parent data
public Patient Patient { get; set; }
public int PatientId { get; set; }
public Organization Organization { get; set; }
public int OrganizationId { get; set; }
}
My DTOs
public class AppointmentDto
{
public int Id { get; set; }
public int Order { get; set; }
public string PatientName { get; set; }
public PatientDto Patient { get; set; }
}
public class PatientDto
{
public string Name { get; set; }
}
First Case
I want to set new ordering for appointments within a day. I send list of JSON objects with IDs of appointments to be changed and their respective orders.
The service action:
[HttpPost]
public IHttpActionResult UpdateOrder(List<AppointmentDto> dto)
{
_unitOfWork.Appointments.UpdateOrder(dto);
_unitOfWork.Complete();
return Ok();
}
The service call:
// Handler methods
var rearrangeAppointments = function (event, ui) {
// Json object to pass
var orderedAppointments = [];
// Looping through appointments
var i = 0;
$("#sortable").children().each(function () {
// Set new order
i++;
orderedAppointments.push({ "Id": this.getAttribute("data-id").toString(), "Order": i.toString() });
});
// Call service
appointmentsService.updateOrder(orderedAppointments, done, fail);
};
var updateOrder = function (orderedAppointmens, done, fail) {
$.ajax({
url: "/api/appointments",
method: "POST",
data: orderedAppointmens,
dataType: "Json"
})
.done(done)
.fail(fail);
};
The service is called successfully, but the passed list is always empty. I debugged the JavaScript code and the array of JSON object is built successfully. Also debugged the MVC code and tested the service Postman, it works very fine. This drop is passing the list of objects from client to server.
Second Case
This time it’s a get call. I want to get list if appointments if a specific date to update the view.
The service action:
public IEnumerable<AppointmentDto> GetAppointments(DateTime date)
{
var organizationId = _unitOfWork.ApplicationUsers.GetOrganizationId(User.Identity.GetUserId());
var appointments = _unitOfWork.Appointments.GetAppointments(date, organizationId);
return appointments.Select(Mapper.Map<Appointment, AppointmentDto>);
}
The service call:
$("#datepicker").datepicker({
// TODO: Refactor to pettern
onSelect: function (dateText, inst) {
var selectedDate = $(this).datepicker('getDate');
var date = JSON.stringify(selectedDate);
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: "json",
url: "/api/appointments",
data: date,
success: function (appointments) {
alert("Service call succeeded!")
alert(appointments.length);
}
})
.fail(function () {
alert("Failure!");
});
}
});
When I test the code without passing a date (hardcoding the date into the action method) it works very well. When I add the date to the parameters (in the action method and the AJAX call), it does not work at all.
I've tried many links and articles from here and other sources with no success, like below:
Pass a datetime from javascript to c# (Controller)
Pass Date Values from Ajax Call to MVC
and more that I could not add here.
I think my major problem in the two cases in passing data.
What am I missing here?

for the second case : Do you sent date-time ?? if you do that the URL may contains ":" (12:00) & this type of character is denied by the HTTP request

After some tracing with one friend, and reviewing some other articles and questions...
First Case (passing list of objects)
I reformatted the array of objects using JSON.stringify(orderedAppointmens), and added contentType: 'application/json; charset=utf-8' to the service call. The code should look like below:
var updateOrder = function (orderedAppointmens, done, fail) {
orderedAppointmens = JSON.stringify(orderedAppointmens);
$.ajax({
url: "/api/appointments",
method: "POST",
data: orderedAppointmens,
contentType: 'application/json; charset=utf-8',
dataType: "Json"
})
.done(done)
.fail(fail);
};
Second Case (passing a Date object)
I removed the Json dataType from the service call and concatenated the date to the URL like below:
$.ajax({
url: "/api/appointments?date=" + selectedDate.toISOString(),
type: "GET",
success: function (appointments) {
alert(appointments.length);
}
});
This worked fine and the Date object is passed to the DateTime object in backend successfully.

Related

Ajax Post (Model binded) passing null to the controller

I am making an AJAX POST request to the controller (ASP.NET Core MVC), yet the value for the parameter is coming through as null. I tried several solutions given on StackOverflow. But, I couldn't correct it. Please help.
My view collects class fees information. There may have more than one payment.
$(function () {
$('#sendSlip').click(function (e) {
e.preventDefault();
let fees = new Array(); //To store payment info
let tb = $('#feesTable:eq(0) tbody');
//Collecting info of each payment
tb.find("tr").each(function () {
let row = $(this);
let fee = {};
if (row.find('input:checkbox:first').is(':checked')) {
fee.ClassId = row.find("TD").eq(0).html();
fee.FeeId = row.find("TD").eq(1).html();
fee.Amount = row.find(".fee").html();
fee.Month = row.find(".month").html();
fees.push(fee);
}
});
//Arranging data to send to controller
var data = {
fees: fees,
Bank: $(".bank").val(),
PaidAmount : $(".amount").val(),
PaidDate : $(".date").val()
};
console.log(data);
$.ajax({
type: 'POST',
url: '#Url.Action("StudentPayment_Create", "StudentPayment")',
contentType: "application/json",
headers: { 'RequestVerificationToken': gettoken() },
data: //{ data: JSON.stringify(data) },
JSON.stringify(data) ,
})
});
});
Model
public class StudentPaymentSlipVM
{
public StudentPaymentPaidClassVM fees { get; set; }
public string Bank { get; set; }
public DateTime PaidDate { get; set; }
public int PaidAmount { get; set; }
}
Controller
public ActionResult StudentPayment_Create([FromBody] List<StudentPaymentSlipVM> data)
{
---
}
Object details at runtime
From your attached screenshot for data to be passed to the controller, the data's structure was unmatched with the data model the controller expected.
Assume the data structure for the front-end is correct.
Controller should expect that the received data is a StudentPaymentSlipVM object. While in the StudentPaymentSlipVM object, the fees is a StudentPaymentPaidClassVM array.
Model
public class StudentPaymentSlipVM
{
public List<StudentPaymentPaidClassVM> fees { get; set; }
public string Bank { get; set; }
public DateTime PaidDate { get; set; }
public int PaidAmount { get; set; }
}
Controller
public ActionResult StudentPayment_Create([FromBody] StudentPaymentSlipVM data)
{
}
While from your JQuery part, make sure that your data object to be passed to API must be matched with the data type as your model in the back-end.
var data = {
fees: fees,
Bank: $(".bank").val(),
PaidAmount : parseInt($(".amount").val()),
PaidDate : $(".date").val()
};
I tried to pass my data to controller by binding to a ViewModel (StudentPaymentSlipVM) which has all required definitions. But I couldn't do it. So I changed the way and pass my object to Controller as following way now it is working.
And also I would like to thanks Yong Shun.
Changed the JQuery code
$.ajax({
type: 'POST',
url: '#Url.Action("action", "controller")',
headers: { 'RequestVerificationToken': gettoken() },
data: dataObj,
})
I changed the Controller
[HttpPost]
public ActionResult StudentPayment_Create(List<StudentPaymentPaidClassVM> Fees, string Bank, decimal PaidAmount, DateTime PaidDate)
{
.....
}

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:

ajax post on MVC .NET does not pass array correctly

I have a simple modal that uses select2 to get a list of Products from the server. User can multiple choose products and hit Ok to refine a search.
My following setup grabs the data from the modal and does an ajax call against a Controller action with a strongly typed view model that matches what the JS is trying to send via the ajax call.
Ajax:
var exploreFilters = {
"type" : exploreType,
"products" : $('#s2id_select2-products').select2('data'),
"locations" : $("#page-report__data").data("criteria__locations"),
"companies" : $("#page-report__data").data("criteria__companies"),
"usertypes" : $("#page-report__data").data("criteria__usertypes"),
"groupusers" : $("#page-report__data").data("criteria__groupusers"),
"datestart" : $("#page-report__data").data("criteria__datestart"),
"dateend" : $("#page-report__data").data("criteria__dateend")
};
$.ajax({
dataType: "html",
type: "POST",
url: "/Report/Group/FilteredView",
data: exploreFilters,
success: function(html) {
if($.trim(html) === "")
$targetSection.html('<div class="page-report__empty">No data found. Please adjust your search filters and try again.</div>');
else
$targetSection.html(html);
},
error: function(xhr, text, err) {
if(text === "timeout")
$targetSection.html('<div class="page-report__empty">The request timed out. Please try again.</div>');
else
$targetSection.html('<div class="page-report__empty">There has been an error.</div>');
}
});
Right before the ajax call goes to the controller I inspect the content and structure of exploreFilters:
Here is how the form data looks on the POST request:
On the other side I got a controller which takes a strongly-typed parameter with a structure similar to what exploreFilters has:
public ActionResult FilteredView(ReportCriteriaViewModel criteria)
{
throw new NotImplementedException();
}
And my strongly-typed view model:
public class ReportCriteriaViewModel
{
public ProductViewModel[] Products { get; set; }
public string[] Locations { get; set; }
public string[] Companies { get; set; }
public string UserTypes { get; set; }
public string GroupUsers { get; set; }
public string DateStart { get; set; }
public string DateEnd { get; set; }
}
public class ProductViewModel
{
public Guid Id { get; set; }
public string Text { get; set; }
}
Once the controller action gets hit I can see that DateStart and DateEnd have been successfully bound but not my list of products.
I cannot change the datatype on the json request, it has to be html because my controller action is going to be returning html.
I've tried changing the capitalization on Id and Text, JSON.stringify (which actually makes the dates not bind anymore)
What am I doing wrong?
Try to add contentType: "application/json" in your Ajax request
$.ajax({
...
contentType: "application/json",
...
});
The problem is in how you are serializing the list:
products[0][id]
products[0][text]
You need to send your list in this format:
products[0].id
products[0].text
id and text should be properties, without the [] otherwise it is treated as an index to a two-dimensional array.
You should try
contentType: "application/json; charset=utf-8"
in the options of the $.ajax call
$.ajax({
dataType: "html",
type: "POST",
url: "/Report/Group/FilteredView",
data: exploreFilters,
contentType: "application/json; charset=utf-8" ....

How to send AJAX/Jquery object to Controller (discrepancy) MVC4

I have had this confusion for a while and it's because of the following reason:
I am trying to send a jquery object
var myObject = {
Title: $('#Title').val(),
Title2: $('#Title2').val(),
Title3: $('#Title3').val(),
};
through an ajax call
$.ajax({
data: { myObjectName = myObject
},
datatype: "json",
url: "myUrl",
cache: false,
error: function (ts)
{//handle error},
success: function (result)
{//handle success}
});
I'm receiving my object in my controller like this:
public ActionResult MyAction(ObjectType myObjectName)
However, when receiving the object from javascript, it does not recognize it as such and just instantiates a new ObjectType.
I know I can send it as a string, serialize it if I put my object inside a form, etc...what I want to know is why this approach seems to work for me sometimes (I have gotten it to work with other ObjectType(s)) and in other instances it doesn't. Does it have anything to do with how complex the object is? Sending an incomplete object? (The latter one doesn't seem to be it since I have sent 'incomplete' objects and the empty fields just get instantiated with null)
ANY insight would be appreciated. Thanks!
Change your code to;
$.ajax({
data: myObject,
datatype: "application/json",
type: "POST",
url: "myUrl",
cache: false,
error: function (ts)
{//handle error},
success: function (result)
{//handle success}
});
Notice that the type is a POST which means you will also need to add [HttpPost] to your ActioResult.
As long as ObjectType is a class with the fields
public class ObjectType
{
public string Title { get; set; }
public string Title2 { get; set; }
public string Title3 { get; set; }
}
Your current code is attempting to bind your model to something which would resemble
public class SomeObject
{
ObjectType myObjectName { get; set; }
}
public class ObjectType{
public string Title { get; set; }
public string Title2 { get; set; }
public string Title3 { get; set; }
}

Modify the postData of jqGrid before call to AJAX-enabled WCF Service

I have an AJAX-enabled WCF service with the following signature:
[OperationContract]
[WebGet]
public JQGridContract GetJQGrid(int entityIndex)
And the following data contract:
[DataContract]
public class JQGridContract
{
[DataContract]
public class Row
{
[DataMember]
public int id { get; set; }
[DataMember]
public List<string> cell { get; set; }
public Row()
{
cell = new List<string>();
}
}
[DataMember]
public int page { get; set; }
[DataMember]
public int total { get; set; }
[DataMember]
public int records { get; set; }
[DataMember]
public List<Row> rows { get; set; }
public JQGridContract()
{
rows = new List<Row>();
}
}
Basically I need to change the postData of the client-side jqGrid to send 'entityIndex' to this service.
I've read how its supposed to function and from what I can tell this should work:
function loadGrid() {
$("#jqGrid").jqGrid({
postData: { entityIndex : function () { // modify the data posted to AJAX call here
return 6;
})
},
gridComplete: function () {
$("#jqGrid").setGridParam({ datatype: 'local' });
},
datatype: function (pdata) {
getData(pdata);
},
And here is the getData() function:
function getData(pdata) {
var params = new Object();
alert(pdata.entityIndex()); // this displays '6', correctly
params.entityIndex = pdata.entityIndex();
$.ajax(
{
type: "GET",
contentType: "application/json; charset=utf-8",
url: "AJAXService.svc/GetJQGrid",
data: JSON.stringify(params),
dataType: "json",
success: function (data, textStatus) {
if (textStatus == "success") {
var thegrid = $("#jqGrid")[0];
thegrid.addJSONData(data.d);
}
},
error: function (data, textStatus) {
alert('An error has occured retrieving data!');
}
});
Ive confirmed the following in Firebug:
1) The json params are correct : {"entityIndex":6}
2) The AJAX service returns JSON data to the grid, its just the wrong data
And here is the wierd part:
I logged the 'entityIndex' thats actually working inside the WCF operation -- and its ALWAYS coming up as 0?
Thanks.
I will not criticize the style of your program. I could write too many things about this. :-)
You current main problem could be solved with the usage JSON.stringify(pdata.entityIndex()) instead of JSON.stringify(params) or with the usage of another BodyStyle of the WFC method (see here for details)
I got it working, it is close to what Oleg said, just that you do not need to do JSON.stringify.
If you have WebMessageBodyStyle.WrappedRequest, this works:
data: { entityIndex: pdata.entityIndex() },
OR if you have no BodyStyle, this works:
data: { "entityIndex": pdata.entityIndex() },

Categories

Resources