Json Not hitting controller - javascript

In My code to save Order JSON not hitting controller also there is no Error appearing even in
Browser Console, Only I am getting Error: Order Not Complete!
My controller:
public ActionResult SaveOrder([FromBody]string name, string address, Order[] order)
{
//var settings = new JsonSerializerSettings();
string result = "Error! Your Order Is Not Complete!";
try
{
if (name != null && address != null && order != null)
{
var cutomerId = Guid.NewGuid();
Customer model = new();
model.CustomerId = cutomerId;
model.Name = name;
model.Address = address;
model.OrderDate = DateTime.Now;
db.Customers.Add(model);
foreach (var item in order)
{
var orderId = Guid.NewGuid();
Order O = new();
O.OrderId = orderId;
O.ProductName = item.ProductName;
O.Quantity = item.Quantity;
O.Price = item.Price;
O.Amount = item.Amount;
O.CustomerId = cutomerId;
db.Orders.Add(O);
}
db.SaveChanges();
result = "Successfully! Order Is Complete!";
}
return Json(result);
}
catch (Exception)
{
throw;
}
}
And here is the JavaScript Code:
function saveOrder(data) {
return $.ajax({
contentType : 'application/json; charset=utf-8',
dataType : 'json',
type : 'POST',
url : "/Orders/SaveOrder",
data : data,
success : function (result) {
alert(result);
location.reload();
},
error : function () {
alert("Error!")
}
});
}
//Collect Multiple Order List For Pass To Controller
$("#saveOrder").click(function (e) {
e.preventDefault();
var orderArr = [];
orderArr.length = 0;
$.each($("#detailsTable tbody tr"), function () {
orderArr.push({
productName : $(this).find('td:eq(0)').html(),
quantity : $(this).find('td:eq(1)').html(),
price : $(this).find('td:eq(2)').html(),
amount : $(this).find('td:eq(3)').html()
});
});
var data = JSON.stringify({
name : $("#name").val(),
address : $("#address").val(),
order : orderArr
});
$.when(saveOrder(data)).then(function (response) {
console.log(response);
}).fail(function (err) {
console.log(err);
});
});
I am reading and searching But couldn't find any difference in my code or even knows my mistake, that is why I seeking Help from you please

It looks like you are trying to bind all three arguments [FromBody]string name, string address and Order[] order to the JSON body of your request, but as explained in .NET Core Web API: multiple [FromBody]? you can only have one [FromBody] parameter as the body can only be read once.
Instead, create a top-level DTO corresponding to the JSON in your body, and bind to that:
public class SaveOrderRequestModel
{
public string name { get; set; }
public string address { get; set; }
public Order[] order { get; set; }
}
and then
public ActionResult SaveOrder([FromBody] SaveOrderRequestModel saveOrderRequest)
{
string result = "Error! Your Order Is Not Complete!";
var (name, address, order) = (saveOrderRequest?.name, saveOrderRequest?.address, saveOrderRequest?.order);
if (name != null && address != null && order != null)
{
// Proceed as before

As #dbc said,you can only have one [FromBody] parameter as the body can only be read once.
I think your error may be due to the incorrect JSON format, the controller does not receive the parameters passed by Ajax, you can check if your Json body is like this when it is passed:
Below is my test code,you can refer to it:
View:
#model _2022072501.Models.OrderDTO
<button id="saveOrder" class="btn btn-primary">submit</button>
<script src="https://code.jquery.com/jquery-1.12.4.js" type="text/javascript"></script>
<script>
function saveOrder(data) {
$.ajax({
contentType : 'application/json; charset=utf-8',
dataType : 'json',
type : 'POST',
url : "/Home/SaveOrder",
data : data,
success : function (result) {
alert(result);
location.reload();
},
error : function () {
alert("Error!")
}
});
}
//Collect Multiple Order List For Pass To Controller
$("#saveOrder").click(function (e) {
e.preventDefault();
debugger;
var orderArr = [];
orderArr.push({
productName : "Test1",
quantity : "Test1"
});
orderArr.push({
productName : "Test2",
quantity : "Test2"
});
var data = JSON.stringify({
name : "testName",
address : "testAdress",
order : orderArr
});
$.when(saveOrder(data)).then(function (response) {
console.log(response);
}).fail(function (err) {
console.log(err);
});
});
</script>
Controller:
public IActionResult SaveOrder([FromBody] OrderDTO orderDTO)
{
//var settings = new JsonSerializerSettings();
string result = "Error! Your Order Is Not Complete!";
var (name, address, order) = (orderDTO?.name, orderDTO?.address, orderDTO?.order);
try
{
if (name != null && address != null && order != null)
{
foreach (var item in order)
{
var orderId = Guid.NewGuid();
Order O = new();
O.OrderId = orderId;
O.ProductName = item.ProductName;
O.Quantity = item.Quantity;
//db.Orders.Add(O);
}
//db.SaveChanges();
result = "Successfully! Order Is Complete!";
}
return Json(result);
}
catch (Exception)
{
throw;
}
}
You can cancel your $.each like me and change it to a fixed value, maybe it's more convenient to find the problem

Related

How to call IActionResult from Javascript?

I have an ASP.NET Application and want to call this IActionResult method from the HomeController:
public IActionResult ReadNewestFile(FileInfo filePath) {
String st = System.IO.File.ReadAllText(filePath.ToString());
ChartData chartData = new ChartData();
string[] lines = st.Split("\n");
foreach (var line in lines) {
string[] values = line.Split(',');
try {
chartData = new ChartData {
Timestamp = Convert.ToDateTime(values[0] + "." + values[1]),
Function = Convert.ToString(values[2]),
Duration = Convert.ToInt32(values[4]),
IsError = Convert.ToBoolean(values[5])
};
db.ChartDatas.Add(chartData);
db.SaveChanges();
}
catch (Exception exc) {
exc.ToString();
}
}
return View(chartData);
}
Now I want to get the return value of this method in the site.js file:
$.ajax({
type: "GET",
url: "Home/ReadNewestFile",
success: function(data) {
console.log(data);
}
});
When I try it like this, the browser says "500 Internal Error". Any ideas to solve this problem?

Why some C# api method need [HttpPost] while some don't need it?

I have two methods are in the same controller file to receive data from JavaScript ajax.
First C# api controller code is
public class News
{
public int ID { get; set; }
public string Title { get; set; }
public string Intro { get; set; }
public string Story { get; set; }
public string Images { get; set; }
public DateTime DateModified { get; set; }
public DateTime DateCreated { get; set; }
}
public void InsertData([FromBody]News newsinfo)
{
conn.ConnectionString = mdc.ConnectonString;
cmd.Connection = conn;
if (newsinfo.ID > 0)
{
cmd.CommandText = "UPDATE [News] SET [Title] = N'" + newsinfo.Title + "', [Intro] = N'" + newsinfo.Intro + "', [Story] = N'" + newsinfo.Story + "', [Images] = N'" + newsinfo.Images + "', [DateModified] = #DateModified WHERE [ID] = " + newsinfo.ID;
cmd.Parameters.AddWithValue("#DateModified", DateTime.Now);
}
else
{
cmd.CommandText = "INSERT INTO [News] ([Title], [Intro], [Story], [Images], [DateCreated], [DateModified]) VALUES (N'" + newsinfo.Title + "', N'" + newsinfo.Intro + "', N'" + newsinfo.Story + "', '" + newsinfo.Images + "', #DateCreated, #DateModified)";
cmd.Parameters.AddWithValue("#DateCreated", DateTime.Now);
cmd.Parameters.AddWithValue("#DateModified", DateTime.Now);
}
conn.Open();
int send = cmd.ExecuteNonQuery();
conn.Close();
}
Above code will receive data from this JavaScript
function InsertData() {
var newsData = {
ID: editingID,
Title: $("#txbTitle").val().replace(/[\"]/gm, "\"").replace(/[\']/gm, "''"),
Intro: $("#txbIntro").val().replace(/[\"]/gm, "\"").replace(/[\']/gm, "''"),
Story: $(".ql-editor").html().replace(/[\"]/gm, "\"").replace(/[\']/gm, "''").replace(/http.\/\/[a-z:0-9]+/gm, "").replace(/\/Images.Temp\//gm, "/Images/News/"),
Images: imagesToUpload.replace(/Temp/gm, "News")
$.ajax({
url: "api/Database/InsertData",
method: "POST",
data: newsData,
success: function (result, status, xhr) {
if (imagesToUpload != "") {
var fileslist = {
filenames: ""
}
fileslist.filenames = imagesToUpload;
console.log(fileslist);
$.ajax({
url: "api/FileUpload/StoreImages",
method: "POST",
data: fileslist,
success: function (result, status, xhr) {
ViewState();
},
error: function (xhr, status, error) {
alert(error);
}
});
}
else if (imagesToUpload == "") {
ViewState();
}
},
error: function (xhr, status, error) {
alert(error);
}
});
}
The second C# api controller code is
public class NewsId
{
public int[] id { get; set; }
}
[HttpPost]
public void DeleteData([FromBody]NewsId newsId)
{
conn.ConnectionString = mdc.ConnectonString;
cmd.Connection = conn;
if (newsId.id.Length > 0)
{
foreach (int id in newsId.id)
{
cmd.CommandText = "SELECT [Images] FROM [News] WHERE [Id] = " + id;
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
string images = "";
while (reader.Read())
{
images = reader[0].ToString();
}
conn.Close();
string[] files = Regex.Split(images, ";");
foreach (string file in files)
{
if (file != "")
{
string path = HttpContext.Current.Server.MapPath("~") + Regex.Replace(file, "/Images", "Images");
File.Delete(path); // /Images/Temp/
}
}
cmd.CommandText = "DELETE FROM [News] WHERE [Id] = " + id;
conn.Open();
int d = cmd.ExecuteNonQuery();
conn.Close();
}
}
}
And it's receive data from this JavaScript
function DeletingNews(news_id) {
var newsId = {
id: news_id // news_id is Array
}
$.ajax({
url: "api/Database/DeleteData",
method: "POST",
data: newsId,
success: function (result, status, xhr) {
ViewState();
},
error: function (xhr, status, error) {
alert(error);
}
});
}
I don't understand why the First code doesn't needs to have the [HttpPost] while the Second code needs it otherwise the Ajax will return
405 method not allowed
Both are running fine now but I just don't understand why some's needs [HttpPost] while another's doesn't need it?
By default API Controller provides with get,put,post and delete
By Default Get All is let say IEnumerable GetAll()
By Default Get is string Get(int id)
By Default Post is void Post([FromBody]object value )
By Default Put is void Put(int id,[FromBody]object value )
By Default delete is void Delete(int id)
closely take a look at the signature used and the return types
based on these the action take place.
so now if you want to add a new action lets say Post then you need to decorate it with HttpPost attribute for controller to understand which action to call
Finally, I solve this problem by just reading on Routing in ASP.NET Web API article.
Because my C# API method name is begin with "Delete" that match on Http verb rules.
public void DeleteData([FromBody]NewsId newsId)
{
conn.ConnectionString = mdc.ConnectonString;
cmd.Connection = conn;
if (newsId.id.Length > 0)
I just have to change my Ajax method from "POST" to "DELETE" like the code below then this issue will be solved.
function DeletingNews(news_id) {
console.log(news_id);
var newsId = {
id: news_id
}
$.ajax({
url: "api/Database/DeleteData",
method: "DELETE", // <-- Changed from "POST"
data: newsId,
success: function (result, status, xhr) {
ViewState();
},
error: function (xhr, status, error) {
alert(error);
}
});
}
Or, another solution is change the C# method name from "Delete" to something else and keep the Ajax method with "POST" like the codes below.
public void RemoveData([FromBody]NewsId newsId) // <-- Change method's name from "DeleteData" to "RemoveData"
{
conn.ConnectionString = mdc.ConnectonString;
cmd.Connection = conn;
if (newsId.id.Length > 0)
function DeletingNews(news_id) {
console.log(news_id);
var newsId = {
id: news_id
}
$.ajax({
url: "api/Database/RemoveData", // <-- Change action url from "DeleteData" to "RemoveData"
method: "POST",
data: newsId,
success: function (result, status, xhr) {
ViewState();
},
error: function (xhr, status, error) {
alert(error);
}
});
}

Pass javascript array to c# array/list using $.post without specifing datatype as json

I have a model created in javascript as follows
function Vehicle() {
this.type = 'Vehicle';
this.data = {
VehicleKey: null
}
};
I have a similar model created in c# as follows
public class Vehicle
{
public string VehicleKey { get; set; }
}
Now I am building an array of VehicleKeys in javascript as follows
function GetVehicleDetails(inputarray) {
var vehicleKeys = [];
for (var i = 0; i < inputarray.length; i++) {
var vehicleObject = new Vehicle();
vehicleObject.data.VehicleKey = inputarray[i].VehicleKey ? inputarray[i].VehicleKey : null;
vehicleKey.push(vehicleObject.data);
}
return vehicleKeys ;
}
I am calling the $.post(url, data) as follows
var objectToSend = GetVehicleDetails(selectedVehicles);
var data = JSON.stringify({
'vehicles': objectToSend
});
$.post(url, data)
.done(function (result) {
if (result) {
download(result, 'VehicleReport.xlsx', { type: 'application/octet-stream' });
console.log("Report created successfully");
}
else {
console.log("Error creating report");
}
}).fail(function (error) {
console.log("Error creating report.");
});
The MVC Controller has a method to accept Vehicles with multiple VehicleKeys coming from javascript
public byte[] CreateVehicleReport(List<Vehicle> vehicles)
{
//Generation of report and pass it back to javascript
}
Here I am able to submit the data in javascript as 10 and 11 for Vehicles but when it catches the c#, the count is coming as 0.
Any help would be greatly appreciated.
$.post is not posted Content-Type json data so you need to use $.ajax
function GetVehicleDetails(inputarray) {
var vehicleKeys = [];
for (var i = 0; i < inputarray.length; i++) {
var vehicleObject = {}; // Set Object
vehicleObject.VehicleKey = inputarray[i].VehicleKey ? inputarray[i].VehicleKey : null;
vehicleKeys.push(vehicleObject);
}
return vehicleKeys;
}
var objectToSend = GetVehicleDetails(selectedVehicles);
$.ajax({ type: 'POST',
url: url,
data: JSON.stringify(objectToSend),
contentType: "application/json",
dataType: 'json',
success: function (data) {
alert('data: ' + data);
},
}).done(function () {
if (result) {
console.log("Report created successfully");
}
else {
console.log("Error creating report");
}
}).fail(function () {
console.log("Error creating report.");
});
C# Method
[HttpPost("CreateVehicleReport")]
public byte[] CreateVehicleReport([FromBody]List<Vehicle> vehicles)
{
return null;
//Generation of report and pass it back to javascript
}
I used a similar approach once but with ajax and it went like this:
fill your array directly with the properties inside your class as object { } make sure the names are exactly the same:
function GetVehicleDetails(inputarray) {
var data_Temp = [];
for (var i = 0; i < inputarray.length; i++) {
var _vehiclekey = inputarray[i].VehicleKey ? inputarray[i].VehicleKey : null;
data_Temp.push({ VehicleKey : _vehiclekey });
});
return data_Temp;
}
var objectToSend = GetVehicleDetails(selectedVehicles);
var JsonData = JSON.stringify({ vehicles: objectToSend });
$.ajax({
type: "POST",
contentType: "application/json",
url: "/controllerName/actionName", //in asp.net using mvc ActionResult
datatype: 'json',
data: JsonData,
success: function (response) {
},
error: function (response) {
console.log(response);
}
});
And the ActionResult in the controller should look like this:
[HttpPost]
public ActionResult Create(List<Vehicle> vehicles)
{
//do whatever you want with the class data
}
I don't know if this is helpful for you but this always works for me and i hope it helps.

ASP.NET MVC Ajax submit form with AntiforgeryToken and Serialized Form data with Validation

I am trying to submit a form via ajax like this:
$(document).ready(function () {
$("#form").submit(function (e) {
e.preventDefault();
var token = $('input[name="__RequestVerificationToken"]', this).val();
var form_data = $(this).serialize();
$.ajax({
url: "#Url.Action("SaveRole", #ViewContext.RouteData.Values["controller"].ToString())",
method: "POST",
data: form_data,
contentType: "application/json",
success: function (result) {
console.log(result);
},
error: function (error) {
console.log(error);
}
});
return false;
console.log(form_data);
});
});
This contacts this controller:
[HttpPost]
[ValidateAjax]
[ValidateAntiForgeryToken]
public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
{
//var role = rolesData.GetByName(Input);
var result = this.Json(new
{
Output = Input
}, JsonRequestBehavior.DenyGet);
return result;
}
Right now, I'm getting errors that my RequestVerificationToken field is not being submitted but I'm not sure how I can combine it with my form data. By default, when I serialize my form data, it already sends this token but for some reason my controller still fails it.
Also, how do I use the modelstates to show my form validations? Right now they are returned as json objects.
EDIT:
AjaxValidate Attribute:
public class ValidateAjax : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
return;
var modelState = filterContext.Controller.ViewData.ModelState;
if (!modelState.IsValid)
{
var errorModel =
from x in modelState.Keys
where modelState[x].Errors.Count > 0
select new
{
key = x,
errors = modelState[x].Errors.
Select(y => y.ErrorMessage).
ToArray()
};
filterContext.Result = new JsonResult()
{
Data = errorModel
};
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
}
}
}
When I submit an empty form, this is what is returned:
0:{key: "RoleName", errors: ["The Role Name field is required."]}
When you use the jQuery .serialize() method, it generates query string format (i.e. ..&name=value&..., which needs to be sent using the default contentType - i.e 'application/x-www-form-urlencoded; charset=UTF-8'.
Remove the contentType: "application/json", from the ajax options.
In addition, your var token = $('input[name="__RequestVerificationToken"]', this).val(); line of code is not necessary - the token is included when you use .serialize()
$("#form").submit(function (e) {
e.preventDefault();
// Add the following if you have enabled client side validation
if (!$(this).valid()) {
return;
}
var form_data = $(this).serialize();
$.ajax({
url: "#Url.Action("SaveRole")",
method: "POST",
data: form_data,
success: function (result) {
... // see notes below
},
error: function (error) {
console.log(error);
}
});
// return false; not necessary since you have used e.preventDefault()
console.log(form_data);
});
To return ModelState errors, remove your ValidateAjaxAttribute - returning a BadRequest is not appropriate (which is intended to indicate that the server could not understand the request due to invalid syntax).
Instead modify the POST method to return a JsonResult that includes the errors (note there is no need to return the model)
public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
{
if (ModelState.IsValid)
{
return Json(new { success = true });
}
else
{
var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0).Select(k => new { propertyName = k, errorMessage = ModelState[k].Errors[0].ErrorMessage });
return Json(new { success = false, errors = errors });
}
}
Then in the success callback, if there are errors, loop through them and find the corresponding <span> element generated by your #Html.ValidationMessageFor() and update its contents and class names
success: function (result) {
if (result.success) {
return;
}
$.each(result.errors, function(index, item) {
// Get message placeholder
var element = $('[data-valmsg-for="' + item.propertyName + '"]');
// Update message
element.append($('<span></span>').text(item.errorMessage));
// Update class names
element.removeClass('field-validation-valid').addClass('field-validation-error');
$('#' + item.propertyName).removeClass('valid').addClass('input-validation-error');
});
},

ASP.NET MVC Unknown Action when delete is pressed

I have a problem, when I try to delete something, it gives me the following error message:
"Error: Unknown Action"
This is my controller:
[Authorize(Roles = "Admin, Staff")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int? id)
{
string result = null;
try
{
if (id == null)
{
result = HIQResources.errorMessageUnknownAction;
return new JsonResult { Data = result };
}
StudentViewModel vm = new StudentViewModel();
StudentDetail studentDetail = studentManager.GetStudentDetailById(id.Value);
if (studentDetail == null)
{
result = HIQResources.errorMessageUnknownRecord;
return new JsonResult { Data = result };
}
int deleteResult = studentManager.Delete(id.Value);
if (deleteResult == 1)
{
vm.Alert.SetSuccessMessage(HIQResources.messageOperationSuccess);
TempData["alert"] = vm.Alert;
result = HIQResources.messageOperationSuccess;
return new JsonResult { Data = result };
}
else
{
vm.Alert.SetErrorMessage(HIQResources.errorMessageUnableToExecuteOperation);
TempData["alert"] = vm.Alert;
result = HIQResources.errorMessageUnableToExecuteOperation;
return new JsonResult { Data = result };
}
}
catch (DbUpdateException ex)
{
Log.AddLogRecord(LogManager.LogType.Warning, LogManager.LogPriority.Low, LogManager.LogCategory.Teacher, ex.Message, ex.StackTrace, base.GetLoggedUser());
result = HIQResources.errorMessageUnableToDeleteRecord;
return new JsonResult { Data = result };
}
catch (Exception ex)
{
Log.AddLogRecord(LogManager.LogType.Error, LogManager.LogPriority.High, LogManager.LogCategory.Inscription, ex.Message, ex.StackTrace, base.GetLoggedUser());
result = HIQResources.errorMessageExceptionOccurred;
return new JsonResult { Data = result };
}
}
This is my Javascript:
$('#ModalDeleteButton').on("click", function (e) {
var token = $('input[name="__RequestVerificationToken"]').val();
$.post("/Student/Delete/",
{
__RequestVerificationToken: token,
id: id
},
function (data) {
$('#myModal .close').click();
var baseurl = '#Url.Action("Index")';
var url = baseurl + "?message=" + data;
window.location.href = url;
});
});
I would need more specific details on this error, it seems to me that the controller and the javascript is right, so I don't really know what possibly can be.
If you're going to call $.post then you need to put the [HttpPost] attribute above the method definition. Otherwise, it just assumes that method is actually a GET (which is why the action is "unknown")
EDIT:
Try changing your $.post to this:
$.ajax({
type: "POST",
data: {
__RequestVerificationToken: token,
id: id
},
success: function(data) {
$('#myModal .close').click();
var baseurl = '#Url.Action("Index")';
var url = baseurl + "?message=" + data;
window.location.href = url;
}
});

Categories

Resources