Ajax call to controller results in 400 error - c#

I have the follow Ajax call that points to a controller function:
<script type="text/javascript">
$(document).ready(function () {
$('#AddNote').click(function () {
$('#AddNote').addClass("disabled");
var txtNote = document.getElementById('note');
var result = document.getElementById('result');
result.innerText = "Adding note...";
$.ajax({
url: "#Url.Action("AddNoteAsync", "Leads")",
type: "POST",
data: { leadId: #Model.Id, note: txtNote.value },
async: true,
success: function (data) {
// removed
},
});
});
});
</script>
When I click the AddNote button I see the "Adding note..." message display and then nothing else happens. When I check the console in chrome, it reads:
:44309/Leads/AddNoteAsync:1 - Failed to load resource: the server responded with a status of 400 ()
So I know 400 means bad request but I'm not sure why it's happening. I've tried:
Added quotes to the "leadId" and "note" field in data - made no difference.
Added alert boxes to show the value of #Model.Id and txtNote.value before the AJAX call to verify they are correct - they are.
Put a breakpoint in the AddNoteAsync function in my controller - it's never hit
Hard coded the url field to /Leads/AddNoteAsync - made no difference
Since the controller function is never being hit I'm assuming something is wrong with the &.ajax part but I cannot figure out what.
Edit: The controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddNoteAsync(int? leadId, string note)
{
ViewData["AddedNote"] = false;
if (leadId == null)
{
return RedirectToAction("Index", new { initials = User.Identity.Name });
}
var lead = await _context.Leads.FirstOrDefaultAsync(m => m.Id == leadId);
if (lead == null)
{
return RedirectToAction("Index", new { initials = User.Identity.Name });
}
var ownsLead = await LeadBelongsToCurrentUser(leadId.Value, User.Identity.Name);
if (!ownsLead)
{
return RedirectToAction("Index", new { initials = User.Identity.Name });
}
_context.LeadNotes.Add(new LeadNoteModel()
{
LeadId = leadId.Value,
Note = note,
NoteDate = DateTime.Now
});
await _context.SaveChangesAsync();
ViewData["AddedNote"] = true;
return Content("Success");
}

You should accept parameters as Model while making POST request(Recommended). Proposed Model will be -
public class NoteModel
{
public int? leadId { get; set; }
public string note { get; set; }
}
and Action can be -
public async Task<IActionResult> AddNoteAsync(NoteModel model)
{
}
Also Jquery can be -
<script type="text/javascript">
$(document).ready(function () {
$('#AddNote').click(function () {
$('#AddNote').addClass("disabled");
var txtNote = document.getElementById('note');
var result = document.getElementById('result');
var postData = { leadId: #Model.Id, note: txtNote.value };
result.innerText = "Adding note...";
$.ajax({
url: "#Url.Action("AddNoteAsync", "Leads")",
type: "POST",
data: JSON.stringify(postData),
async: true,
success: function (data) {
// removed
},
});
});
});

Fixed this. I was missing this from my AJAX request:
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="f"]').val());
},
And this from my Startup.cs:
services.AddAntiforgery(options =>
{
options.FormFieldName = "f";
options.HeaderName = "XSRF-TOKEN";
});

Related

How do I delete from the database in Asp.Net Core via Ajax?

This script is supposed to send a ProductId to the home controller's Delete-method, and the controller should make the appropriate Remove-operation:
$('[name="DeleteItem"]').click(function (e) {
$.ajax({
type: "DELETE",
url: "#Url.Action('Delete','Home')",
data: { id: $('DeleteItem#data-id').val() },
success: function () {
alert("success!");
window.location.replace("#Url.Action('Index', 'Home')");
},
error: function (data) {
alert("Error: " + data.id);
}
});
});
This is the form:
<form asp-action="Update">
#foreach (var item in Model.ShoppingCartItems)
{
#item.ProductTitle
<input asp-for="#item.Quantity" />
<button name="DeleteItem" data-id="#item.ProductId">DELETE</button>
}
<button type="submit">Update quantity</button>
</form>
This is the controller's Delete-method (I don't have the ShoppingCartId, so I'm getting it based on SessionId, which is stored in the ShoppingCarts-table):
[HttpDelete]
//[ValidateAntiForgeryToken] // <-- Do I need this in this case?
public async Task<IActionResult> Delete(
[Bind("ShoppingCartItemProductId")]
ViewModelAddToCart model)
{
// Initialize session to enable SessionId
HttpContext.Session.SetString("_Name", "MyStore");
string SessionId = HttpContext.Session.Id;
var ShoppingCart = new ShoppingCart()
{
SessionId = SessionId
};
var ShoppingCartItem = new ShoppingCartItem()
{
ProductId = model.ShoppingCartItemProductId,
};
if (ModelState.IsValid)
{
// Find ShoppingCart containing current SessionId.
var cartInfo =
(from Cart in _context.ShoppingCarts
where Cart.SessionId == SessionId
select new { TempId = Cart.Id })
.SingleOrDefault();
if (cartInfo != null)
{
ShoppingCartItem.ShoppingCartId = cartInfo.TempId;
}
// Find ShoppingCartItem containing current ProductId:
var cartItemInfo =
(from CartItem in _context.ShoppingCartItems
where (CartItem.ShoppingCartId == ShoppingCartItem.ShoppingCartId &&
CartItem.ProductId == model.ShoppingCartItemProductId)
select new { TempId = CartItem.Id })
.FirstOrDefault();
if (cartItemInfo != null)
{
// Delete ShoppingCartItem
ShoppingCartItem.Id = cartItemInfo.TempId;
_context.ShoppingCartItems.Remove(ShoppingCartItem);
}
await _context.SaveChangesAsync();
return RedirectToAction("Index", "Home");
}
else
{
return View("Index", "Home");
}
}
Edit I have made some changes to my code, and now I receive "Error: undefined" in an alert. That is because the error: in the ajax is triggered, and the data-object is not defined. Why is that? And a second question is what is the controller supposed to return? As I understand, not a RedirectToAction.
what is "deleteitem"
you should have some id or class for the button in your case class should be easy
<button name="DeleteItem" class = "deleteitemevent" data-id="#item.ProductId">DELETE</button>
$(".deleteitemevent").click(function (e) {
}
[HttpPost]
[ValidateAntiForgeryToken]
//^^yes you should for any post... but since you insist on
//doing ajax calls...
//you will have to research how to build this up... from JS and inject with the ajax call..
public async Task<IActionResult> Delete(
[Bind("ShoppingCartItemProductId")]
ViewModelAddToCart model)
{
//...
}
$('[name="DeleteItem"]').click(function (e) {
var dataid = $(this).attr('data-id'); // because name was used for control not id
$.ajax({
type: "POST",
url: "#Url.Action('Delete','Home')",
data: { id: dataid },
success: function () {
alert("success!");
window.location.replace("#Url.Action('Index', 'Home')");
},
error: function (data) {
alert("Error: " + data.id);
}
});
});
I think you have a long way to go... There are easier ways of doing this without needing ajax calls...

Parsing string AngularJS $http to .NET Core controller

I'm trying out AngularJS in combination with NET Core. Currently trying to parse a "string username", "string password" and "bool rememberMe", but both strings are null no matter what I do. I've even tried parsing a constant value as seen below, the parameter "test", but even that doesn't work. I've confirmed in Fiddler that the script is in fact parsing the value, so the controller basically just can't "fetch it".
Below is my AngularJS loginController code.
var login = angular.module('login', []);
login.controller('LoginController',
[
'$scope', '$http', '$window', function ($scope, $http, $window) {
$scope.submit = function () {
var data = { test: ':D' };
$http({
method: 'POST',
url: '/admin',
data: data
}).then(function success(response) {
alert(response.data.test);
});
}
}
]);
Below is the code for my ActionResult meant to fetch the value being posted to it.
[HttpPost]
public IActionResult Index(string test)
{
return Json(new
{
test,
bla = "BLA"
});
//if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
//{
// if (UserSystem.Login(username, password, rememberMe, HttpContext))
// {
// HttpContext.Response.StatusCode = (int)HttpStatusCode.Accepted;
// return Json(new
// {
// returnUrl = "/admin/dashboard"
// });
// }
//}
//HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
//return Json(new
//{
// error = "Username and/or password do not match"
//});
}
I've also tried specifying the Content-Type, but also without luck. Either way, in Fiddler the request always seems to per default be application/json.
I hope someone can help me. Thanks!
The solution was to request an object in the controller, rather than "string username", "string password" and "bool rememberMe".
The controller now looks like this:
public class LoginModel
{
public string Username { get; set; }
public string Password { get; set; }
public bool RememberMe { get; set; }
}
[HttpPost]
public IActionResult Index([FromBody]LoginModel model)
{
if (!string.IsNullOrEmpty(model.Username) && !string.IsNullOrEmpty(model.Password))
{
if (UserSystem.Login(model.Username, model.Password, model.RememberMe, HttpContext))
{
HttpContext.Response.StatusCode = (int)HttpStatusCode.Accepted;
return Json(new
{
returnUrl = "/admin/dashboard"
});
}
}
HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(new
{
error = "Username and/or password do not match"
});
}
And the AngularJS controller now looks like this:
var login = angular.module('login', []);
login.controller('LoginController',
[
'$scope', '$http', '$window', function ($scope, $http, $window) {
$scope.submit = function () {
var data = {
username: $scope.username,
password: $scope.password,
rememberMe: $scope.rememberMe
};
$http({
method: 'POST',
url: '/admin',
data: data
}).then(function success(response) {
$window.location.href = response.data.returnUrl;
}, function fail(response) {
swal('Error!', response.data.error, 'error');
});
}
}
]);

How to return MVC view to JQuery post success delegate

I have the following JQuery method for posting data to a action in my MVC contorller:
$('#btnAddNewTest').on("click", function () {
var date = $('#HIVTestTestDate').val();
var result = $('#HIVTestTestResult').val();
var cd4 = $('#HIVTestCD4Count').val();
var pID = $('#PatientID').val();
var dataToSend = { patientID: pID, testDate: date, resultID: result, cd4Count: cd4 };
$.post("/HIVInformation/AddHIVTest/", dataToSend, function (receivedData) {
location.reload(false); //Don't want to do this
});
return false;
});
Here is the Action method in my controller:
[HttpPost]
public ActionResult AddHIVTest(Guid patientID, DateTime testDate, Guid resultID, int cd4Count)
{
MvcPatientDetailsHIVViewModel model = new MvcPatientDetailsHIVViewModel(patientID);
model.LoadAllData();
try
{
//add the HIV Test
model.HIVTestResult = new Common.Models.PatientHIVTestModel()
{
ID = Guid.NewGuid(),
PatientID = patientID,
TestDate = testDate,
HIVTestResultID = resultID,
CD4Count = cd4Count
};
//call the add method
model.AddHIVTestResults();
}
catch (Exception ex)
{
ModelState.AddModelError("", ex);
}
return View("Details", model);
}
If I comment out the 'location.reload(false);' my page does not get refreshed. How do I serialize my Mvc view to be returned in the function (receivedData) delegate of the post? How do I display my view then from within the JQuery code?
if i may, i would suggest to you to use ajax, partial views, and a container div for example to load the result in it.
Example:
Script:
$(document).ready(function () {
$("#btnAddNewTest").on("click", function () {
$.ajax({
url: '#Url.Action("YourAction", "YourController")',
type: 'post',
data: {
yourData1: value1,
yourData2: value2,
},
success: function (result) {
$('#dynamicContent').html(result);
}
});
});
});
Controller:
public ActionResult YourAction(int yourData1= 1, int yourData2 = 0)
{
return PartialView("~/yourviewPath/_YourPartialView.cshtml", yourResultModel)
}
Html:
<div id="dynamicContent" class="Float_Clear">
#Html.Partial("~/yourviewPath/_YourPartialView.cshtml", Model)
</div>
Live example that I created using the same concept here

Retrieving data from Ajax POST in asp.net

I have an ajax POST like this
$(document).ready(function () {
var pcontent = document.body.innerHTML;
var url = new URI();
$.ajax({
url: url,
type: "POST",
data: { "pcontent": pcontent },
success: function (data) {
alert($(data).find(".right-panel").html());
},
complete: function () {
},
error: function (jqXHR, error, errorThrown) {
if (jqXHR.status) {
alert(jqXHR.responseText);
} else {
alert("Something went wrong");
}
}
});
return false;
});
I am little confused how i could retrieve data (pcontent) that i post here in my code behind.actually in a specific class file i need to implement this logic .
You have to create a controller action:
public class HomeController: {
// model
public class PDocument {
public string pcontent {get;set;}
}
[HttpPost]
public ActionResult SaveDocument(PDocument pcontent){
// do something
return new JsonResult() { Data = new { Success = true } };
}
}
JS:
$.ajax({
url: "Home/SaveDocument",
type: "POST",
data: { "pcontent": pcontent}
...});
Note:
You don't need to create a model on server if set
$.ajax({
url: "Home/SaveDocument",
type: "POST",
data: pcontent
});
// server side
public ActionResult SaveDocument(string pcontent){
// do some thing
}
For security reason, your html must be encoded before calling ajax
In case you new to mvc, then this is a good way to start: http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-controller

Get data from controller

In my controller:
public ActionResult ViewPage()
{
Obj object = new Obj();
object.id = 3;
var JsonItem = Model.getItem(object);
return Json(JsonRfc, JsonRequestBehavior.AllowGet);
}
Client-side
$(document).ready(function () {
$.getJSON({
url: 'ViewPage',
function(data) {
console.log(data);
}
});
});
I'm not logging anything in my console (console.log(data) returns nothing). What am I missing here? When I click on the ActionLink ViewPage, it should go into the model and do some stuff. After I want to get it from the client-side to generate a list view.
Perhaps you are missing something.
Try
$(document).ready(function () {
$.getJSON({
url: 'ViewPage',
success: function(data) {
console.log(data);
}
});
});

Categories

Resources