Validate Anti forgery key not working with ajax post - javascript

I have tried to use validate antiforgery token with ajax post request but the response is that no root element found .
i remove the antiforgery token it works perfectly .
Here is my code :
javascript ;
function Save() {
let GroupName = GetElementValue("GroupName");
let GroupId = GetElementValue("GroupId");
var Group = {
__RequestVerificationToken: gettoken(),
GroupId: :1",
GroupName: "My Group Name"
};
if (IsFormValid("GroupForm")) {
AjaxPost("/Groups/AddGroup", Group).done(function () {
GetGroups();
});
}
}
function gettoken() {
var token = '#Html.AntiForgeryToken()';
token = $(token).val();
return token;
}
function AjaxPost(url, data) {
return $.ajax({
type: "post",
contentType: "application/json;charset=utf-8",
dataType: "json",
responseType: "json",
url: url,
data: JSON.stringify(data)
});
}
I have also tried this :
$.ajax({
type: "POST",
url: "/Groups/AddGroup",
data: {
__RequestVerificationToken: gettoken(),
GroupId: 1,
GroupName: "please work"
},
dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
});
Here Is The backend :
[HttpPost]
[ValidateAntiForgeryToken]
public void AddGroup([FromBody] GroupView Group)
{
if (Group.GroupName.Trim().Length>0)
{
bool existed = _context.Groups.Any(x => x.GroupName.ToLower().TrimEnd().Equals(Group.GroupName.ToLower().TrimEnd()));
if (!existed)
{
Groups group = new Groups()
{
GroupName = Group.GroupName
};
_context.Groups.AddAsync(group);
_context.SaveChanges();
int? groupId = group.GroupId;
}
}
}
And Here Is My Class GroupView
public class GroupView
{
public string GroupId { get; set; }
public string GroupName { get; set; }
}
I want to use the method where i send the serial token with my data normally ,
how can i make it works ?
any help!

In ASP.NET Core you can pass antiforgery token either via form or headers. So I can suggest 2 solutions for you.
Solution 1. Headers
In order to let the framework read token from headers you need to configure AntiforgeryOptions and set HeaderName to non null value. Add this code to Startup.cs
//or if you omit this configuration
//HeaderName will be "RequestVerificationToken" by default
services.AddAntiforgery(options =>
{
options.HeaderName = "X-CSRF-TOKEN"; //may be any other valid header name
});
And pass antiforgery token in AJAX
function Save() {
//..
//no need to set token value in group object
var Group = {
GroupId: "1",
GroupName: "My Group Name"
};
//..
}
function AjaxPost(url, data) {
return $.ajax({
type: "post",
contentType: "application/json;charset=utf-8",
dataType: "json",
responseType: "json",
headers: {
"X-CSRF-TOKEN": gettoken()
},
url: url,
data: JSON.stringify(data)
});
Solution 2. Form
You have already tried to pass token via form but it didn't work. Why? The reason is that the default implementation of IAntiforgeryTokenStore (is used for reading tokens from request) cannot read antiforgery token from json but reads it as form data. If you want to make it work then don't stringify request data and remove contentType property from $.ajax call. JQuery will set appropriate content type and serialize data respectively for you.
//all other original code is unchanged, group needs to contain a token
function AjaxPost(url, data) {
return $.ajax({
type: "post",
dataType: "json",
responseType: "json",
url: url,
data: data
});
Also you need to remove [FromBody] attribute from action parameter to let model binder properly bind model in this case
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddGroup(GroupView group)

For FromBody, it will bind the model from application/json, but CSRF would not read the token from body.
For the simplest way, you could add the header with RequestVerificationToken.
Controller
[HttpPost("/Groups/AddGroup")]
[ValidateAntiForgeryToken]
public void AddGroup([FromBody] GroupView Group)
{
}
Client
<script type="text/javascript">
$(document).ready(function(){
var Group = {
__RequestVerificationToken: gettoken(),
GroupId: 1,
GroupName: "My Group Name"
};
AjaxPost("/Groups/AddGroup", Group).done(function () {
GetGroups();
});
});
function gettoken() {
var token = '#Html.AntiForgeryToken()';
token = $(token).val();
return token;
}
function AjaxPost(url, data) {
return $.ajax({
type: "post",
contentType: "application/json;charset=utf-8",
dataType: "json",
responseType: "json",
url: url,
headers: {
"RequestVerificationToken": gettoken()
},
data: JSON.stringify(data)
});
}
</script>

Related

Unable to call controller method from js

[HttpPost]
[Route("mapchanged")]
public ActionResult mapchanged(string latitud, string longitud)
{
Session["Latitude"] = latitud;
Session["Longitude"] = longitud;
return RedirectToAction("search?what=&by=bnm");
}
$.ajax({
type: "POST",
async: false,
url: url, // '#Url.Action("mapchanged")',
data: {
latitud: map.getCenter().lat(),
longitud: map.getCenter().lng()
},
dataType: "json",
contentType: 'application/json; charset=utf-8',
cache: false,
success: function(data) {
alert('Success');
},
error: function(err) {
alert('error = ' + err.status);
}
});
The above code is not working - it's giving error 404. Also tried var url = '"Home/mapchanged/"' but it's also not working. The ajax code is in map.js file.
Do you have a view for that action? Plus it's an ajax post, you can't redirect to another action while doing ajax post. Try to return json from that action and see if it works.
return Json(new { true }, JsonRequestBehavior.AllowGet);
I tried to reproduce source code. It had some issues with current code.
Missed configure for Route attribute at RouteConfig class, without this configure [Route] annotation/attribute not work.
routes.MapMvcAttributeRoutes()
In ajax call did not use JSON.stringify for data
var data = {
latitud: map.getCenter().lat(),
longitud: map.getCenter().lng()
};
$.ajax({
type: "POST",
async: false,
url: '#Url.Action("mapchanged")',
data: JSON.stringify(data),
dataType: "json",
contentType: 'application/json; charset=utf-8',
cache: false,
success: function (data) {
alert('Success');
window.location.href = data.url;
},
error: function (err) {
alert('error = ' + err.status);
}
});
You should return Json object with url property instead of RedirectToAction
[HttpPost]
[Route("mapchanged")]
public ActionResult mapchanged(LongLat obj)
{
Session["Latitude"] = obj.latitud;
Session["Longitude"] = obj.longitud;
//return RedirectToAction("search?what=&by=bnm");
return Json(new {url = "search?what=&by=bnm"});
}
public class LongLat
{
public double latitud { get; set; }
public double longitud { get; set; }
}

ajax post global function vs repeat the same function for each request

I have something that i do not understand .
I do have a global function AjaxPost()
that take url and data than send them to backend .
it calls the function but the parameters are always null .
So i take the same content of the function and used it directly in the request , it works perfectly .
this One Doesn't work //example : AjaxPost("/Road/DeleteRoad", road);
function AjaxPost(url, data) {
return $.ajax({
type: "post",
url: url,
contentType: "application/json;charset=utf-8",
dataType: "json",
data: JSON.stringify(data)
});
}
this one works perfectly
$.ajax({
type: "post",
url: "/Road/DeleteRoad",
contentType: "application/json;charset=utf-8",
dataType: "json",
data: JSON.stringify(road)
});
Here the action method
[HttpPost]
public async Task<IActionResult> DeleteRoad([FromBody]r road)
{
int.TryParse(road.RoadID, out int RoadID);
if (RoadID > 0)
{
await _road.DeleteRoad(RoadID);
}
return RedirectToAction("Index");
}
Here is the class r
public class r
{
public string RoadID { get; set; }
}
Here Is The Road object
//for example :
var road ={
RoadID :4,
}
Maybe you are not passing the road parameter correctly?
The following code works, sending two calls to the server. The server correctly retrieves the RoadID value. Here's the javascript:
"use strict";
$(document).ready(() => {
var road = { RoadID: 4 };
// First call
$.ajax({
type: "post",
url: "/home/DeleteRoad",
contentType: "application/json;charset=utf-8",
dataType: "json",
data: JSON.stringify(road)
});
// Second call
ajaxPost("/home/DeleteRoad", road);
}
function ajaxPost(url, data) {
return $.ajax({
type: "post",
url: url,
contentType: "application/json;charset=utf-8",
dataType: "json",
data: JSON.stringify(data)
});
}
The C# code is:
public class Road
{
public string RoadID { get; set; }
}
[HttpPost]
public async Task<ActionResult> DeleteRoad([System.Web.Http.FromBody]Road road)
{
Debug.WriteLine($"Road ID = { road.RoadID }");
return RedirectToAction("Index");
}
The server's output is:
Road ID = 4
Road ID = 4
Hope this helps :)

Error while calling Webapi in my asp.net project

This is my api code that return successfull json data while using get method
public Question[] Get() {
getQuestion obj = new AllDataAccess.getQuestion();
return obj.questionList().ToArray();
}
This is my post method data that accept the value and save in database
public void Post([FromBody] string question) {
SaveQuestion obj = new AllDataAccess.controller.SaveQuestion();
obj.savaData(question);
}
This is the method that call my api
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'http://localhost:53893/api/values',
data: "{'question':'" + $("#submit").value + "'}",
dataType: 'json',
async: false,
success: function(data, status) {
console.log(status);
},
error: function(err) {
console.log(err);
}
});
Now the problem is when i post the data with one textbox value its give me a message in console that "nocontent" and record save in data base with null value
It seems that your ajax url is wrong. You should specify the action name (post). Also, use JSON.stringify to retrieve proper json from javascript object.
var postData = { question:$("#submit").val() };
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'http://localhost:53893/api/values/post',
data: JSON.stringify(postData),
dataType: 'json',
success: function (data,status) {
console.log(status);
},
error: function (err) {
console.log(err);
}
});
In the server side, you should create a model class for Post method;
public class PostInput
{
public string Question { get; set; }
}
And then Post method looks like;
[HttpPost]
public void Post([FromBody]PostInput input)
{
SaveQuestion obj = new AllDataAccess.controller.SaveQuestion();
obj.savaData(question);
}
If you want to use FromBody, you can do so.
JavaScript
$.ajax({
type: "POST",
//default content-type, could be omitted
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
url: 'http://localhost:53893/api/values/post',
data: {'': $("#submit").val()}
});
API action
[HttpPost]
public void Post([FromBody]string question)
{
SaveQuestion obj = new AllDataAccess.controller.SaveQuestion();
obj.savaData(question);
}
You had these issues.
Wrong content-type for your ajax call.
Data was not posted correctly.
val() should be used instead of .value.
API action should be decorated with [HttpPost].

Pass json from js to controller

Data doesn't passing to controller, always null
My script in view:
function deleteRecords() {
var selected = [];
$('#myTable input:checked').each(function () {
selected.push($(this).attr('id'));
});
$.ajax({
url: '/Home/DeleteRecords',
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: { "json": JSON.stringify(selected) },
error: function () {
alert("Error!");
}
});
}
My home controller method:
[HttpPost]
public IActionResult DeleteRecords(string AllId)
{
return null;
}
send ajax request data like below,
$.ajax({
url: '/Home/DeleteRecords',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(selected),
error: function () {
alert("Error!");
}
});
and receive the data in action like
[HttpPost]
public IActionResult DeleteRecords(string[] AllId)
{
return null;
}
It need to pass the action. Hope it helps to you.
with the code in your question, try below to get the json
System.Web.Context.Current.Request.Form["json"]
if you want some more graceful stuff, you need to put FromBody attribute in your parameter signature
DeleteResults([FromBody] string json)
Name your property in the Post the same as your method so that the automatic binding picks it up. - Turns out this doesn't matter for single object.
The data Object you were creating was not parse-able by .net, use JSON.stringify directly for the data payload.
Note: The change in Home controller since you are passing an array of string.
function deleteRecords() {
var selected = [];
$('#myTable input:checked').each(function () {
selected.push($(this).attr('id'));
});
$.ajax({
url: '/Home/DeleteRecords',
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(selected),
error: function () {
alert("Error!");
}
});
}
For your home controller method:
[HttpPost]
public IActionResult DeleteRecords(string[] AllId)
{
return null;
}

Jquery Ajax and MVC5 httpPost no value received

I try to send values from my view to my controller.
The method in my controller is called but the value(s) still remain NULL.
Here is the Javascript part:
GUIRequests.prototype.SetNewItemDeliveryValues = function () {
var modelNumberID = this.GetValue('#ModelNumberID');
this.Request.GetPreOrderIDForModelNumberID(modelNumberID); //InventValueRequest
this.Request.GetShortfallAndOverdeliveryInNewItemDelivery(modelNumberID);
}
InventValueRequest.prototype.GetPreOrderIDForModelNumberID = function (_modelNumberID) {
this.CallAjax("/NewItemDelivery/GetPreOrderIDForModelNumberID", _modelNumberID, CallbackMethods.SetPreOrderID);
}
//Private
InventValueRequest.prototype.CallAjax = function (_url, _data, _successFunctionPointer) {
$.ajax({
type: 'POST',
url: _url,
contentType: 'application/json',
data: JSON.stringify(_data),
success: _successFunctionPointer,
error: InventValueRequest.HandleError
});
}
Asp.Net MVC5 (C#) part
[HttpPost]
public ActionResult GetPreOrderIDForModelNumberID(string _modelnumberID)
{
String preOrderID = "";
if (_modelnumberID == null)
{
preOrderID = "No value received";
}
else
{
//Do something
}
return Json(preOrderID);
}
What could be the problem with my code ? why don't I receive any values in my C# part ? It seems that the values get send correctly, at least the payload contains the values I would expect.
_data should have the property _modelnumberID like following.
_data = {'_modelnumberID': '1'}
try below code :
$.ajax({
type: 'POST',
dataType: 'text',
url: _url,
contentType: 'application/json',
data: "_modelnumberID=" + _data,
success: _successFunctionPointer,
error: InventValueRequest.HandleError
});
The Ideal solution would be to use a view model.
public class Create
{
public string _modelnumberID{get;set;}
}
And your HttpPost action would be accepting an object of this
[HttpPost]
public ActionResult View(Create model)
{
// do something and return something
}
and ajax will be
$('.submit').click(function () {
var myData = {
_modelnumberID: _data
}
$.ajax({
url: '/Controller/Action',
type: 'POST',
data: myData,
processData: false
}).done(function () {
}).fail(function () {
});
});
$.ajax({
type: 'POST',
url: _url+"?_modelnumberID="+ _data,
success: _successFunctionPointer,
error: InventValueRequest.HandleError
});
Try this.

Categories

Resources