controller doesn't get hit by jquery ajax : asp.net mvc 5 - c#

I have the below form
<form class="regForm" id="frmRegistration" method="post">
<h3>Register Customer Patient</h3>
#Html.ValidationSummary(true)
#Html.LabelFor(m => m.LastName)
#Html.TextBoxFor(m => m.LastName, new { #class = "form-control cfield", required = "required", autofocus = "autofocus" })
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName, new { #class = "form-control cfield", required = "required" })
#Html.LabelFor(m => m.MiddleName)
#Html.TextBoxFor(m => m.MiddleName, new { #class = "form-control cfield", required = "required" })
#Html.LabelFor(m => m.BirthDate)
#Html.TextBoxFor(m => m.BirthDate, new { #class = "form-control cfield", required = "required" })
#Html.LabelFor(m => m.Address)
#Html.TextBoxFor(m => m.Address, new { #class = "form-control cfield", required = "required" })
<button type="submit" id="btnSave" class="btnreg btn btn-primary form-control">REGISTER</button>
<button type="button" onclick="clearTexts();" class="btnClear btn btn-danger form-control">CLEAR</button>
Below is the controller action method which I want to trigger/call
[HttpPost]
public ActionResult AddCustomerPatient(Customer _Customer)
{
using (var db = new DCDBEntities())
{
db.Customers.Add(_Customer);
db.SaveChanges();
}
return Json(new {registeredCustomer="ok"});
}
Below is my jquery ajax which doesn't work
$("#btnSave").click(function () {
e.preventDefault();
var PotentialCustomer = {
"LastName": 'A',
"FirstName": 'A',
"MiddleName": 'A',
"BirthDate": 'A',
"Address": 'A'
};
$.ajax({
type: 'POST',
url: '/Registration/AddCustomerPatient',
data: 'JSON.stringify(PotentialCustomer),',
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (response) {
alert("Successfully Registered Customer/Patient!");
}
});
});
Problem 1.) The controller action method is not getting hit ( I placed a breakpoint)
Problem 2.) How can I pass the Model to the controller action method and save it via linq to entities.
I've been searching and tried a lot but still not able to get it done.
Below is the routconfig
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I tried to put a breakpoint in the GET or first method of my controller , whenever I click the "REGISTER" button it gets hit and not the [HttpPost] , why is that?
public ActionResult RegisterCustomerPatient()
{
return View();
}
[HttpPost]
public ActionResult AddCustomerPatient(Customer _Customer)
{
using (var db = new DCDBEntities())
{
db.Customers.Add(_Customer);
db.SaveChanges();
}
return Json(new {registeredCustomer="ok"});
}
do i need to create a view for HTTPPOST action method?

var formData = $('#frmRegistration').serialize();
$.ajax({
type: 'POST',
url: '#Url.Action("AddCustomerPatient", "Registration")',
data: formData,
success: function (response) {
alert("Successfully Registered Customer/Patient!");
}
});
better to serialize the form data and send it to controller action method

data: 'JSON.stringify(PotentialCustomer),'
Please remove single quotes .
It will be fine
data: JSON.stringify(PotentialCustomer),

Problem is line
data: 'JSON.stringify(PotentialCustomer),',
and
click(function () {
// e is undefined here. Add e as parameter in function.
e.preventDefault();
JSON.stringify should be used as funtion not string. In above it is used as string. Change it to following (assuming all fields are string in model)
$("#btnSave").click(function (e) {
e.preventDefault();
var PotentialCustomer = {
"LastName": 'A',
"FirstName": 'A',
"MiddleName": 'A',
"BirthDate": 'A',
"Address": 'A'
};
$.ajax({
type: 'POST',
url: '/Registration/AddCustomerPatient',
data: JSON.stringify(PotentialCustomer),
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (response) {
alert("Successfully Registered Customer/Patient!");
}
});

there is a , inside data
data: 'JSON.stringify(PotentialCustomer),',
next am not sure but try
data:{'_customer':'PotentialCustomer'};
instead of data.strinify

Problem 1.) The controller action method is not getting hit
I think it is caused by wrong URL of ajax post. You could try to open Network tab of Developer Tool on Browser to confirm that. It you ajax post return HTTP status 404, you should update the URL of your ajax post.
One way to get correct URL is using the #Url.Action to add URL attribute of your submit button.
<button type='button' id='btnSave' data-url='#Url.Action("AddCustomerPatient", "Registration")' class='btnreg btn btn-primary form-control'>REGISTER</button>
Then you could get this value inside click function like this
$("#btnSave").data('url')
Problem 2.) How can I pass the Model to the controller action method and save it via linq to entities.
After getting correct URL, you should update your click function
$("#btnSave").click(function () {
var formData = $('#frmRegistration').serialize();
$.ajax({
type: 'POST',
url: $("#btnSave").data('url'),
data: formData,
success: function (response) {
alert("Successfully Registered Customer/Patient!");
}
});
});
Alternative method
I guess you want to make an ajax post instead of submit form, so you could try another simple method as below.
The razor code
#using (Html.BeginForm("AddCustomerPatient", "Registration", FormMethod.Post, new { id = "frmRegistration"))
{
...
<button type="submit" id="btnSave" class="btnreg btn btn-primary form-control">REGISTER</button>
<button type="button" onclick="clearTexts();" class="btnClear btn btn-danger form-control">CLEAR</button>
}
The script
$(function () {
$("#frmRegistration").on('submit', function (e) {
e.preventDefault(); // prevent the form's normal submission
var $form = $(this);
var dataToPost = $form.serialize();
$.post($form.attr('action'), dataToPost)
.done(function(response, status, jqxhr){
// this is the "success" callback
})
.fail(function(jqxhr, status, error){
// this is the ""error"" callback
});
})
})

your ajax request should be like this
$("#btnSave").click(function (e) { //added e
e.preventDefault();
var _Customer= { //changed the name to name of parameter of action
"LastName": $("#LastName").val(),
"FirstName": $("#FirstName").val(),
"MiddleName": $("#MiddleName").val(),
"BirthDate": $("#BirthDate").val(),
"Address": $("#Address").val()
};
$.ajax({
type: 'POST',
url: '/Registration/AddCustomerPatient',
data: JSON.stringify(_Customer), //removed '' and corrected the format
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (response) {
alert("Successfully Registered Customer/Patient!");
}
});
});
JSON.stringify is a function so it should not be placed inside '' and JSON.stringify(_Customer) object name should match the name of parameter of Action which is Customer _Customer and also you used e.preventDefault(); without adding e in parameter

Related

Using ajax to update fields in a view based off of dropdown onchange with a method in the DAL

I have a view that has a dropdown that is generated by a linq statement when the view is populated.
<div class="form-group">
#Html.LabelFor(m => m.OrderID, "Order ID")
<div>
#Html.DropDownListFor(m => m.OrderID, Model.Orders, "Select Order ID",
new { #id = "orderDropdown" })
</div>
</div>
I have 2 other fields in the view that need to be updated with the data retrieved from the database.
<div class="form-group">
#Html.Label("Final Weight")
<div id="finalWeight">
#Html.DisplayFor(m => m.FinalWeight)
</div>
</div>
<div class="form-group">
#Html.Label("Initial Weight")
<div id="initialWeight">
#Html.DisplayFor(m => m.InitialWeight)
</div>
</div>
This is the ajax that I got from the link below:
<script>
$("#orderDropdown").change(function (event) {
$.ajax({
url:"???" + $(this).val(),/* not sure what to use*/
data: { id: $(this).val()},
cache: false,
type: "GET",
dataType: "html",
success: function (data, textStatus, XMLHttpRequest) {
$("#divinitialWeight").html(data);
}
});
});
Here is the controller code
[HttpGet]
[OpenAction]
public async Task<float> GetInitialWeight(int sid)
{
var initialWeight = await Manager.FindInitialFilterWeightBySID(sid);
return initialWeight.MeanWeight;
}
The method is in a Data Access Layer that is only referenced in the main project. The way I would call it in the controller would be like below and pass it the orderId :
Entities.Manager.FindInitialWeight(orderId);
Entities.Manager.FindFinalWeight(orderId);
I came across this SO question and it's close to what I need but the only issue is the url: because the data retrieval method is not in my controller...it is in the data access layer that is only a reference. Also the orderId is being passed as a parameter.
How can I call that method from ajax and pass it the orderId from the url: of the ajax call?
You can call the controller method from JQuery like this
if the JQuery code is within the razor view
url: '#Url.Action("GetInitialWeight")',
data: { sid: $(this).val()},
I actually had to create a GET method in my controller that contacted the DAL with the passed parameter from the javascript
[HttpGet]
[OpenAction]
public async Task<ActionResult> GetInitialWeight(int sid)
{
var initialWeight = await Manager.FindInitialFilterWeightBySID(sid);
return Json(new { initialWeight.MeanWeight }, JsonRequestBehavior.AllowGet);
}
Then change the javascript as such
<script>
$("#sidDropdown").change(function (event) {
var url = "/Controller/GetInitialWeight/";
var data = { sid: $(this).val() };
var dataType = "json";
$.get(
url,
data,
function (response) {
$("div#initialWeight").text(response.MeanWeight)
console.log(response.MeanWeight);
}, dataType);
});

How to send AntiForgeryToken (CSRF) along with FormData via jquery ajax

So I want to POST fileUpload along with AntiForgeryToken via AJAX. Here's my code :
View
#using (Html.BeginForm("Upload", "RX", FormMethod.Post, new {id = "frmRXUpload", enctype = "multipart/form-data"}))
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(m => m.RXFile, new {.type = "file"})
...rest of code here
}
<script>
$(document).ready(function(){
$('#btnRXUpload').click(function () {
var form = $('#frmRXUpload')
if (form.valid()) {
var formData = new FormData(form);
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
formData.append('__RequestVerificationToken', fnGetToken());
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
})
}
})
})
</script>
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload()
{
//rest of code here
}
I get
The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster
error via fiddler. Any idea how to solve this issue?
I FOUND THE ANSWER :
<script>
$(document).ready(function(){
$('#btnRXUpload').click(function () {
var form = $('#frmRXUpload')
if (form.valid()) {
var formData = new FormData(form.get(0)); //add .get(0)
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
})
}
})
})
</script>
FINALLY FOUND THE ANSWER :
I just need to add .get(0) in the form, here's the code :
<script>
$(document).ready(function(){
$('#btnRXUpload').click(function () {
var form = $('#frmRXUpload')
if (form.valid()) {
var formData = new FormData(form.get(0)); //add .get(0)
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
//formData.append('__RequestVerificationToken', fnGetToken()); //remark this line
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
})
}
})
})
</script>
You need to add the token to the request headers, not the form. Like this:
if (form.valid()) {
var formData = new FormData(form);
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: 'multipart/form-data',
processData: false,
headers: {
'__RequestVerificationToken': fnGetToken()
}
})
}
Edit
Looking back at how I solved this problem myself, I remember that the standard ValidateAntiForgeryTokenAttribute looks in the Request.Form object which doesn't always get populated for an AJAX request. (In your case, the file upload needs a multipart/form-data content type, whereas a form post for the CSRF token needs application/x-www-form-urlencoded. You set contentType=false, but the two operations need conflicting content types, which may be part of your problem). So, in order to validate the token on the server, you will need to write a custom attribute for your action method that checks for the token in the request header:
public sealed class ValidateJsonAntiForgeryTokenAttribute
: FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["__RequestVerificationToken"]);
}
}
More info (a bit out of date now) here.

Returning Json Data From Controller to View ASP.NET MVC

I am trying as the title says to return a Json message from the Controller to the View after it validates.
I have made a breakpoint, and I know that the code works from Controller side, and that my JavaScript calls with success the ActionResult now. How do I display that message in the View?
There are two buttons, stamp in and stamp out. If the user stamps in twice, it should get a message, same with stamp out. I have two ActionResults who are indentical except some message and string changes.
Controller:
[HttpPost]
public ActionResult CreateStamp(Stamping stampingmodel)
{
var validateMsg = "";
stampingmodel.Timestamp = DateTime.Now;
stampingmodel.StampingType = "in";
if (stampingmodel.User == null || ModelState.IsValid)
{
var idValidated = db.Users.Find(model.UserId);
if (idValidated != null)
{
var stamp =
db.Stampings.Where(s => s.UserId == stampingmodel.UserId)
.OrderByDescending(s => s.Timestamp)
.FirstOrDefault();
if (stamp.StampingType == stampingmodel.StampingType)
{
if (stampingmodel.StampingType == "in")
{
validateMsg = "Stamped Twice In A Row!";
}
}
else
{
if (stampingmodel.StampingType == "in")
{
validateMsg = "Stamped In, Welcome.";
}
}
}
db.Stampings.Add(stampingmodel);
db.SaveChanges();
}
return Json(new {Message = validateMsg });
JavaScript:
$(document).ready(function () {
$("#stampInBtn").click(function () {
var userId = $("#userId").val();
$.ajax({
url: "ComeAndGo/CreateStamp",
type: "POST",
dataType: "json",
data: {
userId: userId,
}
});
});
View:
<input type="text" id="idUser" class="form-control" />
<br />
<input type="submit" value="IN" id="stampInBtn" />
I have more code inside the View of course; divs, head, body, title and scripts. But it's perhaps a little irrelevant.
What should I do to successfully show those messages?
Regards.
Add a success function to the ajax call
$.ajax({
url: "ComeAndGo/CreateStamp",
type: "POST",
dataType: "json",
data: { userId: userId },
success: function(data) {
// data contains the value returned by the server
console.log(data);
}
});
So if the controller returns
return Json("This is a message");
the value of data will be "This is a message". Note the return value can be a complex type or a partial view
You are getting the value of $("#userId"), but your input has an id of idUser.
Try making your input:
<input type="text" id="userId" class="form-control" />
Also it would be a good idea to provide your Stamping model structure as it seems that you only pass the user id in your post and nothing else.
Change your javascript code as following:
$(document).ready(function () {
$("#stampInBtn").click(function () {
var userId = $("#userId").val();
$.ajax({
url: "ComeAndGo/CreateStamp",
type: "POST",
dataType: "json",
data: {
userId: userId,
},
success: function(data) {
var objData= jQuery.parseJSON(data);
alert(objData.Message );
},
error: function (request, status, error) {
alert(request.responseText);
}
});
});
});

Redirect with Ajax POST

i'm new with ajax and i'm trying to call a post action from an ajax method like that
$(".buttonSelection").click(function () {
selectedId = $(this).parents('tr:first').children('td:first').children('input:first').attr('value');
$.ajax({
// Call MaSelection action method
url: "/DemandeLocation/MaSelectionOffre",
data: { id: selectedId },
type: 'Post',
success: function (msg) {
window.location.replace('#Url.Content("~/DemandeLocation/MaSelectionOffre")');
},
error: function (xhr) {
alert("something seems wrong");
}
});
});
my post method goes with success but instead of redirectin me to the MaSelection View it return the first view where i call the method, so i tried to put a "Success" fragment in my ajax method and i puted a location replace by "Ma selection" view but i know that the view lose the id so it become null, how can i do it with Ajax,
here my post action for more details
[HttpPost]
[Authorize(Roles = "Locataire")]
public ActionResult MaSelectionOffre(string id)
{
int DemandeLocationGetbyId = Convert.ToInt32(id);
var selectionOffre = db.SelectionOffreLocationSet.Where(model => model.DemandeLocationPublication_ID == DemandeLocationGetbyId).ToList();
return View("MaSelectionOffre", selectionOffre);
}
use json as datatype;
$(".buttonSelection").click(function () {
selectedId = $(this).parents('tr:first').children('td:first').children('input:first').attr('value');
$.ajax({
// Call MaSelection action method
url: "/DemandeLocation/MaSelectionOffre",
dataType:"json",
data: { id: selectedId },
type: 'Post',
success: function (msg) {
window.location.href = msg.redirect;
},
error: function (xhr) {
alert("something seems wrong");
}
});
});
also you need this ;
Convert object to JSON string in C#
If you want redirect page, after ajax call you should use
...
success: function (msg) {
window.location.href = '#Url.Action("MaSelectionOffre", "DemandeLocation")';
},
...
EDIT
If you want replace result, use something like following:
HTML
<div id="updateTargetId">
//table
//tr
//td
//your button that has cssClass buttonSelection
</div>
JS
$(".buttonSelection").click(function () {
selectedId = $(this).parents('tr:first').children('td:first').children('input:first').attr('value');
$.ajax({
// Call MaSelection action method
url: "/DemandeLocation/MaSelectionOffre",
dataType:"json",
data: { id: selectedId },
type: 'Post',
success: function (msg) {
$("#updateTargetId").html(msg);
},
error: function (xhr) {
alert("something seems wrong");
}
});
});
CONTROLLER (return PartialView)
[HttpPost]
[Authorize(Roles = "Locataire")]
public ActionResult MaSelectionOffre(string id)
{
int DemandeLocationGetbyId = Convert.ToInt32(id);
var selectionOffre = db.SelectionOffreLocationSet.Where(model => model.DemandeLocationPublication_ID == DemandeLocationGetbyId).ToList();
return PartialView("MaSelectionOffre", selectionOffre);
}
i changed my action to a get action and in my button i just added window.location.replace with link and ID
<button type="button" class="buttonSelection" onclick="window.location.replace('#Url.Content("~/DemandeLocation/MaSelectionOffre?id="+item.Publication_ID)')"> <span class="ui-icon ui-icon-cart"></span> </button>

MVC3 JSON Ajax error

I am trying to make an ajax sending data in JSON from a partial view. I get a System.ArgumentException: Invalid JSON primitive: undefined.
When I evaluate the object in a browser data contains an int and two strings. Can anyone tell me what I am doing wrong?
Partial View
#model FTD.Models.FTDAccountExtended
#using (Html.BeginForm()) {
<fieldset>
<legend>Update Policy Number</legend>
#Html.HiddenFor(m => m.account.ftd_accountsid)
#Html.HiddenFor(m => m.OldPolicyNumber)
#Html.TextBoxFor(m => m.account.ftd_policyno)
<input type="button" value="update" id="update" />
</fieldset>
}
<script type="text/javascript">
$(document).ready(function () {
$("#update").click(function () {
var myUrl = '#Url.Content("~/")' + '/Maintenance/UpdatePolicyNumber';
var data = [{ 'ClientNumber': parseInt($("#account_ftd_accountsid").val()), 'OldPolicyNumber': $("#OldPolicyNumber").val(), 'NewPolicyNumber': $("#account_ftd_policyno").val()}];
$.ajax({
url: myUrl,
type: 'POST',
data: data,
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert(data.message);
},
error: function (errMsg) {
alert("Error", errMsg);
}
});
});
});
The controller method is
public ActionResult UpdatePolicyNumber(int ClientNumber, string OldPolicyNumber, string NewPolicyNumber)
{
var message = string.Format("UpdatePolicyNumber CN:{0} OP:{1} NP:{2}", ClientNumber, OldPolicyNumber, NewPolicyNumber);
if (_log.IsDebugEnabled)
_log.Debug(message);
if (!string.IsNullOrEmpty(NewPolicyNumber) && ClientNumber > 0)
{
_entities = new CloseFTD_Entities();
_entities.UpdatePolicyNumber(ClientNumber, OldPolicyNumber, NewPolicyNumber, User.Identity.Name);
}
return Json
(
new
{
message = message
},
JsonRequestBehavior.AllowGet
);
}
I would just try posting the the data as a java script object (as Marc mentioned above)
and remove the content type attribute.
success: function (data) {
alert(data.success);
},
shouldn't this be
success: function (data) {
alert(data.message);
},
Your problem is here
var data = [{ 'ClientNumber': parseInt($("#account_ftd_accountsid").val()), 'OldPolicyNumber': $("#OldPolicyNumber").val(), 'NewPolicyNumber': $("#account_ftd_policyno").val()}];
You are building an array - but your controller excepts the direct values, so just remove the [] brackets:
var data = { 'ClientNumber': parseInt($("#account_ftd_accountsid").val()), 'OldPolicyNumber': $("#OldPolicyNumber").val(), 'NewPolicyNumber': $("#account_ftd_policyno").val()};
That should work.

Categories

Resources