I'm not so expert with ajax, so I find it hard to look for the better answer. I've tried creating separate ".js" file that contains the call for rest service (for validation of user session), but it doesn't work.
My goal is to validate user session before loading my views (in MVC). The only way to use the logic of validating the given session with the database is to call a rest service via url using ajax.
This code works well (inside Home View):
<script type="text/javascript">
$(function () {
$.get('#Url.Action("GetSession", "Auth")', function (getdata) {
if (getdata.UserID && getdata.SessionID && getdata.SourceIP) {
$.post('http://website.com/Rest/Authenticate/ValidateUserSession', JSON.stringify(getdata), function (response) {
if (response == false) { window.location.replace('#Url.Action("SignUp", "Auth")'); }
});
} else {
window.location.replace('#Url.Action("SignUp", "Auth")');
}
});
});
</script>
<h2>
Home</h2>
#*The content here should not appear, unless session is validated.*#
The only problem is that, the process of validation takes 3 to 5 seconds, so the user sees the Home page before the ajax call returns the result whether the validation was successful or not. If validation/response returns false it will redirect to sigup page.
I don't know what is the best practice with this process. For now I jsut don't want the Home view show to the user unless session is validated. Hope I'd explain it well. Please suggest if you have the better idea.
Additional info:
If possible, I like doing this:
<script type="text/javascript">
if(!validated()){
window.location.replace('#Url.Action("SignUp", "Auth")');
}
</script>
<h2>
Home</h2>
#*The content here should not appear, unless session is validated.*#
Why can't you consume the rest service at server side ? Technically there should be no reason for not being able to do that. Here's a tutorial discussing exactly that : http://codebetter.com/johnvpetersen/2012/03/22/accessing-a-asp-net-webapi-rest-service-from-asp-net-mvc/
That should take care of everything. If for some reason that's not possible for you, then you can do the following,
Make your home page a partial view.
Instead of loading home page, load an empty page with processing icon (or whatever message you want to show.)
Talk to the REST service and if got the reply then load Home page's partial view using JQuery else load sign up partial view.
Here's an article discussing how to load MVC partial views using JQuery: http://www.codeproject.com/Articles/34221/JQuery-Partial-Views-in-ASP-NET-MVC
Related
I have a MVC Controller with an Index that will cycle through multiple PartialView as the user goes through the form process.
Here is the Index:
#section pageMain {
<div id="partialView">
#Html.Partial("SelectAccount", SUPR.Models.Account.GetAccounts());
</div>
}
This works fine and I get the SelectAccount page just fine.
My issue is that I have an AJAX call that runs when the user selects a row in a table on the SelectAccount page. What is supposed to happen is that the PartialView is then replaced with another PartialView that displays the details of the selected row. This actually does work, but after about 1 second it cycles back to the SelectAccount PartialView with a query string attached, for some reason, to the URL.
Before
After
Here is the code for the AJAX call:
$.ajax({
type: "GET",
url: "/Review/GetReviewView",
data: { profitCenter: profitCenterNo }
}).done(function (data) {
$('#partialView').html(data);
});
The ONLY that is happening in the controller for GetReviewView is that I'm returning the PartialView with the PartialView name and model. This working because, in that brief moment that I can see the ReviewAccount view, the proper data is in the fields.
Any thoughts as to why this odd behavior is occurring?
Are you capturing the event in JS? If you are triggering off of a click event then add the event parameter to the method and then at the end of the method add:
event.preventDefault()
And see if it still happens. It sounds like a client side JS issue, not a C# issue.
The way you are doing this is actually fine. There used to be a Microsoft library called ASP-AJAX or something, don't remember because I didn't use it much. This library basically allowed you to decorate HTML elements with ASP-AJAX-METHOD , ASP-AJAX-REFRESH-TYPE and it would automatically do something similar to what you are doing now. Go to the Server and retrieve a PartialView.
There are 2 requirements in a secure website in which a form is being posted to an url:
The form will be posted to a new window if authentication ticket is still valid, otherwise the same window will redirect user to the login page.
Posting the form to new window will not invoke popup blocker.
I have gone as far as writing an ajax action to get correct answer on whether auth is still valid or not. But I'm unable to get the redirect code to come outside the script execution context and thus avoid popup blocker. Please help!
JavaScript:
$('#someSystem').click(function () {
//deferred promise?
auth().done(function (result) {
//need to move below code outside this callback without side effects
if (result == 'true') {
var form = $('#ssoForm');
form.submit();
}
else {
window.location.href = "/account/login";
}
});
return false;
});
function auth() {
return $.ajax({ url: '/account/isauthenticated', method: "POST" });
}
HTML for already authenticated user
<form action="/sso/somesystem" id="ssoForm" method="post" target="_blank">
...
<div id="someSystem">Continue</div>
</form>
I don't believe you will be able to do anything short of adjusting the pop-up block to avoid it. If the js could do that it would almost completely defeat the purpose of the blocker. Also you should think about the security of doing your redirect in js because the code is in user space. The user could cancel the redirect from their browser.
Instead why not do the check on the server and use
RedirectToAction()
After reading several jQuery posts and even signalR, this codeproject.com article was the most helpful for my case. It seems there is a simpler way to handle this. Developer does not know whether the authentication is valid or not at a given time, but definitely knows after how long it will expire. This knowledge can be hard coded in a JavaScript and an alert can be sent to the user preemptively (setTimeout), instead of waiting for them to click and then try to figure out. This approach will not let me disturb the popup blocker.
I'm coding an MVC3 application with ajax and I got a situation.
I have to show na Button only if an condition is true. Ok its easy to do.
#if (Model.AAA == ENUM.AAA)
{
<button>OK</button>
}
but this button going to call an ajax function.
Now my doubt is, WHERE A PLACE MY AJAX CODE?
if I do this:
#if (Model.AAA == ENUM.AAA)
{
function OK(){
$.ajax({});
}
<button>OK</button>
}
it's sound ugly code!!!
It's seens that the code it' not in the right place but the ajax code is "safe", I mean, the ajax code will only exist if the button exist.
but if I place my code in head section, An advanced user will be able to call the ajax function.
or if a make an #if clause to enclose the script, I will duplicate code like this
<head type="text/javascript">
#if (Model.AAA == ENUM.AAA){
function OK(){
$.ajax({});
}
}
</head>
....
<body>
....
#if (Model.AAA == ENUM.AAA)
{
<button onclick="OK()">OK</button>
}
....
</body>
So, What is the best practice to face this situation, the best approach?
It sounds almost like you are wanting to use the presence/lack of a snippet of Javascript code to control access to a call on your server. Don't do that.
Your server should always be evaluating if the action can be called by the user in question at that moment. What if the user leaves the page open in their browser, and some application state change happens that would block the user from calling that action... but their browser is still displaying the button? Or if a clever user decides to play around with your URLs by poking around in the source?
I would recommend just putting the javascript in a common location and calling it from there, as that keeps all your Javascript together.
Just have the one conditional in your markup, like you have:
#if (Model.AAA == ENUM.AAA)
{
<button id="OkButton">OK</button>
}
Then tweak your Javascript slightly so you don't include Razor (that way it can be extracted into an external JS file):
<head type="text/javascript">
WireUpButton();
function WireUpButton() {
var okbutton = document.getElementById("OkButton");
if (okbutton) {
okbutton.onclick = OK;
}
}
function OK(){
$.ajax({});
}
</head>
The server should control the request call and check for the correct state. #Andrew Barber points this out, but that is not just leaving the browser open. But the advanced user could share the ajax request, with others that don't have permission, or use it maliciously
Trying to answer the question in a bit more depth, it could be not a simple script like this, but a file or some JS library, maybe you don't have control about the server you ajax is accessing. In that case, you'd probably want to duplicate the verification.
Let me preface this question with the fact that I am very new to MVC.
I have an instance where I am rendering a devexpress grid in a partial view.
#Html.Partial("MyGridPartial", Model)
I need to kick off a javascript function at the moment that the model has been populated via this partial view render. I attempted to do this via this. :
settings.ClientSideEvents.EndCallback
I can get to this point, but at that time I do not have the model itself populated so it does no good. I was wondering if anyone is aware of a generic way of kicking/attaching to a partial view render in order to jump into some clientside javascript code.
If it's a PartialView you're rendering in a View on the serverthen Dave's method would work best. Simply wire-up your code to the DOM ready event.
$(document).ready(function(){
//Javascript logic to fire goes here
});
or if you prever the shorthand version...
$(function(){
//Javascript logic to fire goes here
});
If you're rendering a partial view that is being loaded via Ajax then the same method will work. jQuery will run javascript in the html passed back to the client via Ajax once it's attached to the DOM if I recall correctly (feel free to test this I'm just going by memory about it firing once attached to the DOM, but I believe this is a feature of the load() method), assuming the javascript you want to run is in the response. If it's in the parent page sending the Ajax request then you're best bet is to hook it up to the complete event. (I'm populating the parameter on the client side here)
$("#wrapperAwaitingContent").load("/Grids/MyGridPartial", {id: null /*parameters*/}, function(text, status, xhr){
//Javascript logic to fire goes here
});
For me the url used in the .load() call is resolved using the UrlHelper on the server
$("#wrapperAwaitingContent").load("#Url.Action("MyGridPartial", "Grids")", {id: null /*parameters*/}, function(text, status, xhr){
//Javascript logic to fire goes here
});
You also have the option of doing something similar to this using Unobtrusive Ajax. (I'm populating the parameter on the server side here)
#Ajax.ActionLink("Load Data", "MyGridPartial", "Grids", new { id = null/*parameters*/ }, new AjaxOptions() { UpdateTargetId = "wrapperAwaitingContent", OnComplete="onCompleteMethodName" })
There are more properties you can set for the AjaxOptions other than the element to receive the HTML and the method to call when it's finished but I find I'll reuse functions defined in a shared javascript file and populate them only if they are not already populated from there, something like this...
$("a[data-ajax='true']").each(function () {
var ajaxUpdate = $(this).closest("data-ajax-container");
$(this).attr("data-ajax-update", $(this).attr("data-ajax-update") ? $(this).attr("data-ajax-update") : ajaxUpdate);
$(this).attr("data-ajax-mode", $(this).attr("data-ajax-mode") ? $(this).attr("data-ajax-mode") : "replace");
$(this).attr("data-ajax-success", $(this).attr("data-ajax-success") ? $(this).attr("data-ajax-success") : "AjaxSuccess");
$(this).attr("data-ajax-complete", $(this).attr("data-ajax-complete") ? $(this).attr("data-ajax-complete") : "AjaxComplete");
$(this).attr("data-ajax-failure", $(this).attr("data-ajax-error") ? $(this).attr("data-ajax-error") : "AjaxError");
});
If you are rendering this partial as part of the normal flow of a View being rendered, the answer is NO.
Reason for this is the Partial is converted into a string before the parent View is even rendered. At that point, none of your markup has been seen by the browser, no jscript has been read.
If, on the other hand, you rendered the partial in your JQuery Ready function:
$(document).ready(function() {
I think you would need to use an Action Partial (Partial that gets called by an action method). Action Partials can be called within your JQuery Ready function by referencing the url (restfully):
$('#divMyGridPartial').load('/Grids/MyGridPartial/{id}');
and any follow up jscript/jquery functions can be called within the ready series.
The other advantage of an Action Partial, the Model is formed within the action method and can be created contextually to what you need (ideally hinging off an id passed).
I got a bit of an issue in my ASP.NET MVC project.
I have a chat div in the bottom right corner (like facebook), and of course I do not want this to reload when navigating to all my navigation is ajax.
The problem I am facing is that I use the following code on the top of the view page:
<script type="text/javascript">
$(document).ready(function() {
$('#divTS').hide();
$('a#showTS').click(function() {
$('#divTS').slideToggle(400);
return false;
});
});
</script>
The problem is that this code is only loaded with ajax and does not seem to fire? I would like to run all scripts in the newly loaded view, just as if I hadn't navigated with ajax.
I cannot put this in the site.master as it only loads once and then probably the divs I am trying to hide doesn't exist.
Is there a good way to run scripts in the ajax-loaded div?
You will need to run the scripts in the success callback function of your ajax script. I would recommend you externalizing this into a separate function:
function setupEffects() {
$('#divTS').hide();
$('a#showTS').click(function() {
$('#divTS').slideToggle(400);
return false;
});
}
$(document).ready(function() {
setupEffects();
});
And in the success callback of your script call this function:
success: function(result) {
setupEffects();
}
The Masterpage gets reloaded when you navigate to another View. You can also check if a div exists with $('#div').length > 0.
By the way, "full site" ajax navigation should not be used. Reload your chat on navigation - best put it into a control (makes things easier).