How to Login through AJAX in ASP.NET MVC 3 - asp.net-mvc

No i have been stuck here ... can you please help me out...
$(':submit').click(function (e) {
var username = $('#username').val();
var password = $('#password').val();
var postdata =
{
'Email': username,
'Password': password
};
$.post({
url: 'http://localhost:7651/Home/CheckLogin',
data: postdata,
success: function (msg) {
alert('Hi');
}
});
});
this is not working ...its not calling the action controller somehow...
my controller action is
public string CheckLogin(Users checkuser)
{
if (db.CheckUserLoginDetails(checkuser.Email, checkuser.Password))
{
return "Login Successful:" + checkuser.Email;
}
else
{
return "Login UnSuccessful";
}
}
please help.... also do i need to prevent the defualt behavior of the submit button like e.preventDefault();

Here are the steps you need to do:
Your LoginController would need to validate the login and return the HTML Fragments containing the Login Status. Note that you don't need a fullblown HTML here. Just the fragments containing the result
As you probably know, you can utilize jQuery.ajax that you put in your view. To append the Login Result into the DIV, you could use jQuery.html Here is the snippet that you would need (NOTE: not debugged yet, but roughly something like below)
// Override form submit
$("form").live("submit", function (event) {
event.preventDefault();
var form = $(this);
$.ajax({
// Get the action URL
url: form.attr('action'),
type: "POST",
// get all form variables
data: form.serialize(),
// upon success, the fragment of HTML from the Controller will be stored in loginResultHtml
success: function(loginResultHtml){
// append the html to your login DIV id using jQuery.html function
$(#your-login-status-div-id).html(loginResultHtml);
}
});
});

Related

How to use a custom "__RequestVerificationToken"?

I've made a partial view like this (location: MyController/_Form.cshtml):
<form asp-antiforgery="true">
<input type="button" value="submit" />
</form>
Some actions in Controller:
[HttpPost, ValidateAntiForgeryToken]
public IActionResult Test()
{
return Ok(new { succeeded = true });
}
[HttpPost]
public IActionResult GetTemplate()
{
string template = _viewRender<string>("MyController/_Form", null);
return Ok({ template = template });
}
The _viewRender is a service to convert from partial view to a string.
I've tested with these steps:
Using jquery to make a request from client to server to get the template and append to some div.
let onSuccess = function (data) {
$(data.template).appendTo('.myDiv');
};
$.ajax({
url: '/MyController/GetTemplate',
method: 'POST'
}).done(onSuccess).fail(onError);
And the event to detect submiting form looks like:
$(document).on('click', 'input[type=text]', function () {
let _this = $(this);
let token = _this.parent().find('[name=__RequestVerificationToken]').val();
let onSuccess = function (data) {
console.log(data); // should be: Object:{succeeded:true}
};
$.ajax({
url: '/MyController/Test',
method: 'POST',
data: { __RequestVerificationToken: token },
processData: false,
contentType: false
}).done(onSuccess).fail(onError);
});
When I made the request, I always got error code 404 - not found on Console tab.
I'm sure the path is correct. So, I've tried to remove ValidateAntiForgeryToken attribute from Test action and tried again. It's working fine (request status code 200).
So, I guess the problem (which gave 404 error) came from the token. I've used developer tool to check again and I'm sure that I have a token. But I don't know how to check the token is valid or not.
The token was generated from server. I just made a request to get it and appended to body. Then, re-sent it to server. But server didn't accept it.
Why?
This is how it's done in ASP.NET Core...
In Startup.cs you'll need to setup the anti-forgery header name.
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
You need to do this because by default anti-forgery will only consider form data and we want it to work with ajax too.
In your .cshtml file you'll need to add #Html.AntiForgeryToken() which will render a hidden input with the validation token.
Finally in your ajax code you need to setup the request header before sending.
beforeSend: function(xhr) {
xhr.setRequestHeader("X-XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
}
So in your case the ajax code will look like this.
$.ajax({
url: '/MyController/Test',
method: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader("X-XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
processData: false,
contentType: false
}).done(onSuccess).fail(onError);
Two things.
First, I use a custom filter instead of ValidateAntiForgeryToken. I don't remember why. Probably ValidateAntiForgeryToken doesn't work with AJAX requests.
Here's the code for the custom filter I use.
[AttributeUsage(AttributeTargets.Class)]
public sealed class ValidateAntiForgeryTokenOnAllPostsAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException(nameof(filterContext));
}
var request = filterContext.HttpContext.Request;
// Only validate POSTs
if (request.HttpMethod == WebRequestMethods.Http.Post)
{
// Ajax POSTs and normal form posts have to be treated differently when it comes
// to validating the AntiForgeryToken
if (request.IsAjaxRequest())
{
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie?.Value;
AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
}
else
{
new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
}
}
}
}
Second, the token goes in the request header not the data part. I add it to the header using ajaxSetup in the layout file. That way I don't have to worry about remembering to add it to every AJAX request.
$.ajaxSetup({
cache: false,
headers: { "__RequestVerificationToken": token }
});

Ajax Request issue with ASP.NET MVC 4 Area

Today i discovered something weird, i have regular asp.net mvc 4 project with no such ajax (just post, get). so today i need ajax request, i did an ajax action with jquery in controller and it didn't work out. Here is my code
Areas/Admin/Controllers/BannersController
public JsonResult SaveOrder(string model)
{
bool result = false;
if (!string.IsNullOrEmpty(model))
{
var list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<int>>(model);
result = repository.SaveOrder(list);
}
return Json(result, JsonRequestBehavior.AllowGet);
}
View side (Its in area too)
$(document).ready(function () {
$("#saveOrder").click(function () {
var data = JSON.stringify($("#list_banners").nestable('serialize'));
$.ajax({
url: '#Url.Action("SaveOrder", "Banners", new { area = "Admin" })',
data: { model: data },
success: function (result) {
if (result) {
toastr.success('Kaydedildi.');
}
else {
toastr.error('kaydedilemedi.');
}
},
error: function (e) {
console.log(e);
}
});
});
});
i've already tried everything i know, which is $.post, $.get, ajax options, trying request from out of area etc.. just request can't reach action
and here is the errors ,
http://prntscr.com/297nye
error object
http://prntscr.com/297o3x
Try by specifying the data format (json) you wand to post to server like and Also change the way you pass data object in JSON like this :
var data = $("#list_banners").nestable('serialize');
$.ajax({
url: '#Url.Action("SaveOrder", "Banners", new { area = "Admin" })',
data: JSON.stringify({ model: data }),
dataType: 'json',
contentType: "application/json",
...
I had same issue, but after spending too much time, got solution for that. If your request is going to your specified controller, then check your response. There must be some problem in your response. In my case, response was not properly converted to JSON, then i tried with passing some values of response object from controller using select function, and got what i needed.

Post from partial View change the URL

I have a partial view with a contact form.
My problem is that after the form is posted, the controller is redirecting to the actual URL of the partial view: ("LocalHost:/Views/ContactUs/MoreInformationRequest.cshtml")
I want to keep the same URL and to show only the ViewData["MsgSent"] message.
This is the call to the partial view:
#Html.Partial("~/Views/ContactUs/MoreInformationRequest.cshtml")
The View:
#using (Html.BeginForm( "MoreInformationRequest","ContactUs"))
{
.....
<input type="submit" value="send" /><br />
#ViewData["MsgSent"]
}
The Controller:
[HttpPost]
public ActionResult MoreInformationRequest(ContactUs contacts)
{
.....
ViewData["MsgSent"] = "Message sent!"
return View();
}
You could use a redirect to redisplay the page that loads the partial view:
return RedirectToAction("OriginalAction");
You could also return a specific view, particularly the view from the original action:
return View("OriginalView");
post to the server using jQuery and return false from the javascript function to stop the default processing (i.e. sending to the new url from the controller.
At the beginning I came out with this solution - to redirect to the same page using:
Request.Redirect("~/");
But I did not like this solution so I solved this by using client side code to send the data to the controller:
<script>
var request;
$('#formMoreInformationRequest').submit(function () {
var Name = document.getElementById('Name');
var Phone = document.getElementById('Phone');
// without this the validations in the page are not working.
if (Name.value == "") {
return false;}
else if (Phone.value == "") {
return false; }
else {
$('#overlay').show()
if (request) {
request.abort();
}
// setup some local variables
var $form = $(this);
// let's select and cache all the fields
var $inputs = $form.find("input, select, button, textarea");
// serialize the data in the form
var serializedData = $form.serialize();
// let's disable the inputs for the duration of the ajax request
$inputs.prop("disabled", true);
// fire off the request to /form.php
request = $.ajax({
url: "/ContactUs/MoreInformationRequest",
type: "post",
data: serializedData
});
// callback handler that will be called on success
request.done(function (response, textStatus, jqXHR) {
$('#overlay').hide()
$("#moreInfoMsg").html("Message Sent!");
});
// callback handler that will be called on failure
request.fail(function (jqXHR, textStatus, errorThrown) {
$('#overlay').hide()
// log the error to the console
alert(
"The following error occured: " +
textStatus, errorThrown
);
});
// callback handler that will be called regardless
// if the request failed or succeeded
request.always(function () {
// reenable the inputs
$inputs.prop("disabled", false);
});
// prevent default posting of form
event.preventDefault();
}
</script>

View not refreshing after AJAX post

I have a view (Index.cshtml) with a grid (Infragistics JQuery grid) with an imagelink. If a user clicks on this link the following jquery function will be called:
function ConfirmSettingEnddateRemarkToYesterday(remarkID) {
//Some code...
//Call to action.
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
//alert('Succes: ' + remarkID);
//window.location.reload();
//$('#remarksgrid').html(result);
});
}
Commented out you can see an alert for myself and 2 attempts to refresh the view. The location.reload() works, but is basically too much work for the browser. The .html(result) posts the entire index.cshtml + Layout.cshtml double in the remarksgrid div. So that is not correct.
This is the action it calls (SetEnddateRemarkToYesterday):
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
return RedirectToAction("Index");
}
This is the action it redirects to:
[HttpGet]
public ActionResult Index() {
//Some code to retrieve updated remarks.
//Remarks is pseudo for List<Of Remark>
return View(Remarks);
}
If I don't do window.location.reload after the succesfull AJAX post the view will never reload. I'm new to MVC, but i'm sure there's a better way to do this. I'm not understanding something fundamental here. Perhaps a nudge in the right direction? Thank you in advance.
As you requesting AJAX call, you should redirect using its response
Modify your controller to return JSONResult with landing url:
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Controller");
return Json(new { Url = redirectUrl });
}
JS Call:
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
window.location.href = result.Url
});
After Ajax post you need to call to specific Url..
like this..
window.location.href = Url
When using jQuery.post the new page is returned via the .done method
jQuery
jQuery.post("Controller/Action", { d1: "test", d2: "test" })
.done(function (data) {
jQuery('#reload').html(data);
});
HTML
<body id="reload">
For me this works. First, I created id="reload" in my form and then using the solution provided by Colin and using Ajax sent data to controller and refreshed my form.
That looks my controller:
[Authorize(Roles = "User")]
[HttpGet]
public IActionResult Action()
{
var model = _service.Get()...;
return View(model);
}
[Authorize(Roles = "User")]
[HttpPost]
public IActionResult Action(object someData)
{
var model = _service.Get()...;
return View(model);
}
View:
<form id="reload" asp-action="Action" asp-controller="Controller" method="post">
.
.
.
</form>
Javascript function and inside this function I added this block:
$.ajax({
url: "/Controller/Action",
type: 'POST',
data: {
__RequestVerificationToken: token, // if you are using identity User
someData: someData
},
success: function (data) {
console.log("Success")
console.log(data);
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html'); // parse result (type string format HTML)
console.log(htmlDoc);
var form = htmlDoc.getElementById('reload'); // get my form to refresh
console.log(form);
jQuery('#reload').html(form); // refresh form
},
error: function (error) {
console.log("error is " + error);
}
});

How to manage MVC AJAX responses when in a jQuery dialog

Here is my problem:
Inside a jQuery dialog I have the following code:
<%:Ajax.ActionLink("Yes", "SendClaim", "Claim", new { id = Model.ExpenseId }, new AjaxOptions { UpdateTargetId = "dialog" }, new { #class = "button" })%>
When stuff fails in the controller based on roles I return a partial view that replaces the existing dialog (see UpdateTargetId = "dialog").
When everything works I want to do a redirect to another page (an index of all claims) to stop the user performing additional actions but this entire page is rendered inside the jQuery dialog due to it being an ajax request with an update id.
What is the correct way to approach the problem?
I'm a bit of a novice, but I find I have more control with the following approach instead of using Ajax.ActionLink. Hopefully it helps and I have understood what you want to do correctly.
Claim Controller:
[AcceptVerbs(HttpVerbs.Post)]
public Json Send(int expenseId)
{
// Check user stuff
if(valid)
// do stuff
return new Json(true, JsonRequestBehavior.AllowGet);
else
return new Json(false, JsonRequestBehavior.AllowGet);
}
jQuery
function submitClaim() {
$.ajax({
url: "/Claim/Send",
type: "POST",
dataType: "json",
data: { 'expenseId': <%=Model.ExpenseId> },
success: function (data) {
if(data) { // if successful, redirect
document.location = "Claim/Index";
}
else { //load your partial view into your dialog
$("#idOfYourDialog").load('Claim/Error/');
}
},
error: function (xhr) { }
});
}
html
Submit
Returned an 'All OK' dialog and had the following javascript when the user clicks the ok button:
function redirect() {
document.location = "<%:(String)ViewBag.Redirect %>";
}
$(document).ready(function() {
$(".ui-dialog-titlebar-close").click(function() {
redirect();
});
});
Seems unavoidable - you can't seem to do an RedirectToAction when the controller action has been called from Ajax.ActionLink as the response will be stuck into the updatetargetid.

Resources