I am using knockout and using my custom function given below to make ajax call to controller. if any unhandlled exception occurs it returns entire page as response which results on reponse displaying entire html of page please suggest proper way of handling this
function asyncComputed(evaluator, owner) {
var result = ko.observable(), currentDeferred;
result.inProgress = ko.observable(false); // Track whether we're waiting for a result
ko.computed(function () {
// Abort any in-flight evaluation to ensure we only notify with the latest value
if (currentDeferred) { currentDeferred.reject(); }
var evaluatorResult = evaluator.call(owner);
// Cope with both asynchronous and synchronous values
if (evaluatorResult && (typeof evaluatorResult.done == "function")) { // Async
result.inProgress(true);
currentDeferred = $.Deferred().done(function (data) {
result.inProgress(false);
if (data.hasOwnProperty("HasFailed") == true && data.ErrorCode == 1)//For Session Time Out
{
$("#timeoutmessage")
.html('<div class="modal-backdrop">' +
'<div style="color:white;" class="middle">' +
'<div class="row-fluid"><div>Your session has timed out, please Login here again.</div></div>' +
'</div>')
.show();
}
result(data);
});
evaluatorResult.done(currentDeferred.resolve);
} else // Sync
result(evaluatorResult);
});
return result;
}
and my calling function is
self.currentRevenue = asyncComputed(function () {
self.currentRevenueinProgress(true);
var duration = self.duration();
var location = self.location();
return $.ajax({
url: getCurrentTotalRevenue,
type: "GET",
data: { "durationType": duration, "storeId": location }
}).done(function (result) {
self.currentRevenueinProgress(false);
if (result.hasOwnProperty("HasFailed") == true) {
self.currentRevenueError(true);
}else{alert('success');}
});
i am using asycComputed function for making ajax calls if any of the ajax call thows exception all of the ajax call fails and result html of the page in response.
Can i use filters here Please suggest
You could write a custom action filter on the server which catches the exceptions and changes them into JSON responses.
public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
Then you just have to add the custom attribute to your controller action.
Related
Below is my code from view from my ASP.NET MVC project. I am using datatable to create a table. I am fetching data from a Web API. Data is being returned but while binding I get the error shown here. I tried deleting a lot of code which had buttons. Now I just have code for simply binding it.
datatables warning: table id=patients - ajax error. for more information about this error, please see http://datatables.net/tn/7
jQuery code :
$(document).ready(function () {
debugger;
var table = $("#patients").DataTable({
ajax: {
url: "/api/patients",
dataSrc: ""
},
columns: [
{
data: "First_Name"
},
{
data: "phoneNumber",
render: function (data) {
debugger;
return data.toString().replace(
/(\d\d\d)(\d\d\d)(\d\d\d\d)/g, '$1-$2-$3');
}
},
{
data: "Address"
},
]
});
});
API code from controller:
public IHttpActionResult GetPatients()
{
var patientDto = getdata();
return Ok(patientDto);
}
public IEnumerable<Patient_Response> getdata()
{
IEnumerable<Patient_Response> students = null;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer 0f6af107-6ad2-4665-ad24-f09402d50082");
client.BaseAddress = new Uri("http://localhost:6600/api/");
// HTTP GET
var responseTask = client.GetAsync("patients");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<Patient_Response>>();
readTask.Wait();
students = readTask.Result;
}
else //web api sent error response
{
// log response status here..
students = Enumerable.Empty<Patient_Response>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
return students;
}
What is wrong? I am not able to figure out.
Did you read the documentation: https://datatables.net/manual/tech-notes/7
This occurs when jQuery falls into its error callback handler (this callback built into DataTables), which will typically occur when the server responds with anything other than a 2xx HTTP status code.
That means that your call go the controller, failed to bring any data.
You can use the following code to see what went wrong:
$.fn.dataTable.ext.errMode = 'none';
$('#patients')
.on( 'error.dt', function ( e, settings, techNote, message ) {
alert( 'An error has been reported by DataTables: ', message );
} )
.DataTable();
I have a simple LogIn form, which on LogIn button clicked performs ajax call to ActionResult LogIn(LogInRequest request) in AccountController that returns JsonResult. I have CustomHandleErrorAtribute that inherits from HandleErrorAttribute and redirects to CustomErrorPage.cshtml.
Somwhere in the ActionResult exception is thrown, that should be handled by CustomHandleErrorAtribute and it is handled. Then the CustomErrorPage action is executed but it doesnt actualy return the view. It stays on same LogInPage.
My LogIn action in AccountsController
[AllowAnonymous]
[HttpPost]
[CustomAttributes.CustomHandleError]
public ActionResult Login(LogInRequest request)
{
StandartResponse finalResult = new StandartResponse();
//some code that trows exception
return new JsonResult() { Data = finalResult.Result};
}
My Ajax call on LogIn button clicked:
function LogInUser(s, e) {
var example = { username: UserName.GetValue(), password: Password.GetValue() };
$.ajax({
contentType: "application/json; charset=utf-8",
dataType: 'json',
type: "POST",
url: "/Account/LogIn",
data: JSON.stringify({ request: example }),
success: function (data) {
jQuery.ajaxSettings.traditional = true;
if (data.Status == InfoType.Success) {
alert('success');
var url = "/Home/Index";
window.location.href = url;
}
else {
alert('here');
var result = JSON.stringify(data.Infoes);
popUpErrorMessagePartial.PerformCallback({ message: result });
popUpErrorMessagePartial.Show();
}
},
error: function(){
alert('error');
}
});
}
CustomHandleErrorAttribute:
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result =
new RedirectToRouteResult(new RouteValueDictionary
{
{ "action", "ErrorUnauthorised" },
{ "controller", "CustomErrorPages" },
{ "Area", String.Empty }
});
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
}
After debugging the Action of CustomErrorPage is executed, but then the error in the ajax call is executed, the allert is displayed and no redirection is performed. Do you know how to handle this?
Because you do get an exception, the ajax call itself fails, which is why you get the alert, but you can't redirect to another page inside the server side of an ajax call. Instead you can put the redirect inside the fail block of your ajax call. Something like....
error: function(){
window.location = <put error page url here>
alert('error');
}
I'm using PayPal express checkout (checkout.js V4.0.0) with asp.net mvc to allow a user to pay for data transactions. What I need to do when the express checkout button is clicked is perform some checks on the database and confirm that PayPal can proceed (this is also time related, as the database could be in a locked processing state).
I've setup the Advanced Server Integration and I then call the create-payment controller from the payment section in paypal.Button.render, but this expects a json object with a PaymentID element to be returned. At what point am I able to perform these checks on server side and abort from the paypal process if PayPal can't continue? If a check fails, the server side also needs to return an appropriate error page or message to be displayed.
This is the paypal button code:
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
paypal.Button.render({
env: 'sandbox',
payment: function (resolve, reject) {
var CREATE_PAYMENT_URL = '#Url.Action("PayTransactions","Pending")';
paypal.request.post(CREATE_PAYMENT_URL)
.then(function (data) { resolve(data.paymentID); })
.catch(function (err) { reject(err); });
},
onAuthorize: function(data) {
var EXECUTE_PAYMENT_URL = 'https://my-store.com/paypal/execute-payment';
paypal.request.post(EXECUTE_PAYMENT_URL,
{
paymentID: data.paymentID,
payerID: data.payerID
})
.then(function(data) { /* Go to a success page */ })
.catch(function (err) { /* Go to an error page */ });
},
onCancel: function (data, actions) {
return actions.redirect();
},
onError: function (err) {
// Show an error page here, when an error occurs
}
}, '#paypal-button');
</script>
which at the payment section calls this:
public async Task<string> PayTransactions()
{
// check if payment is still necessary or end of month is running
var condition = await CheckDatabaseIsUsable();
switch (condition)
{
case 1:
ModelState.AddModelError("error", "some error message");
return RedirectToAction("Index", "Pending");
case 2:
ModelState.AddModelError("error", "some other error");
return RedirectToAction("Index", "Pending");
}
var paypalPayment = FormPayPalPaymentObject();
return JsonConvert.SerializeObject(new { paymentID = paypalPayment.PaymentId });
}
The problem is that I am now mixing the ActionResult and json string return types.
You can return json also for the redirection responses and control with javascript when it is a redirection or and ok response.
Server side:
return JsonConvert.SerializeObject(new { redirect= Url.Action("Index", "Pending") });
Javascript:
paypal.request.post(CREATE_PAYMENT_URL)
.then(function (data) {
if(data.redirect)
{
//cancel the flow and redirect if needed
window.location.href = data.redirect;
}else{
resolve(data.paymentID);
}
})
.catch(function (err) { reject(err); });
},
Using an IActionResult object as the return value for the PayTransactions is preferable
public async Task<IActionResult> PayTransactions()
{
...
return Json(new { paymentID = paypalPayment.PaymentId });
}
Also consider that the modelstate errors you are adding are useless because of the redirection.
You can call reject(error) to cancel the payment.
When I make ajax request to the server with breakpoint in the action method it stops on this breakpoint only the first time. After clicking for second, third etc. it goes but never stops on this breakpoint. When I change the method from GET to POST it stops every time. What is the reason for this behaviour ?
CLIENT SIDE:
$(function () {
setListAction();
});
function setListAction() {
$("li.list").on("click", function () {
alert("active");
var id = $(this).attr("file-id");
$.ajax({
type: "GET",
url: "TechAcc/ManageFile/" + id,
beforeSend: function myfunction() {
$("#loading").css("display", "block");
$("#fade").css("display", "block");
},
success: function (data) {
var content = $(data).find("div#content");
$("div#content").html(content.html());
$("#loading").css("display", "none");
$("#fade").css("display", "none");
}
});
});
}
SERVER SIDE:
[HttpGet]
public ActionResult ManageFile(int id = 0)
{
FileModel model = null;
if (id != 0)
model = new FileModel() { File = _repository.GetFileBy(id), GetAllFiles = _repository.GetAllFiles() };
else if (Session["Model"] != null)
model = (FileModel)Session["Model"];
else
model = new FileModel() { GetAllFiles = _repository.GetAllFiles() };
return View(model);
}
if your div with id "content" has list, it will not work.
<div id="content">
if your list is here, it won't work.
...
<li class="list">...</li>
...
</div>
if your design is like that, you need to bind click event after you replace your HTML response. i.e.,
success: function (data) {
var content = $(data).find("div#content");
$("div#content").html(content.html());
//adding code here.
$("div#content").find("li.list").on("click", function() {
//same above click code should come here.
//Note: this newly added code block should not come here in click.
});
$("#loading").css("display", "none");
$("#fade").css("display", "none");
}
I know this is duplicate but I could not get reliable solution(for asp.net web).
I just want to redirect to the login page if session expires.
I have tried following:
1. using jquery status code
$.ajax({
type: "POST",
url: "stream.asmx/SomeMethod",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
//success msg
},
error: function (request, status, error) {
if (status = 403) {
location.href = 'login.aspx';
}
}
});
Problem: this returns same status code(403) for other errors too, which I only expect for session timeout.
2. Sending json message whether session expired
code behind:
if (!object.Equals(HttpContext.Current.Session["User"], null))
{
Id = int.Parse(HttpContext.Current.Session["User"].ToString());
}
else
{
result = from row in dtscrab.AsEnumerable()
select new
{
redirectUrl = "login.aspx",
isRedirect = true
};
}
on $.ajax success:
success: function (msg) {
if (msg.d[0].isRedirect) {
window.location.href = msg.d[0].redirectUrl;
}
else {
//load containt
}
}
Problem: It's somehow desn't invoke ajax success line if session expires(it does return correct json). And even this is not a proper way if I have many number of ajax request in the page(should be handled globally).
However, I saw this post which is really good soltion but it's for mvc using AuthorizeAttribute: handling-session-timeout-in-ajax-calls
So, Is there I can use same concept used in mvc using AuthorizeAttribute in asp.net web api? If not, how I can troubleshoot those issue which I'm facing (any of above two mentioned)?
A 403 status code is going to cause jQuery to call the failure method. Keep the same code behind from your second try, but move the redirect handler to the failure method instead of the success method. In the success method, treat it as you normally would.
Problem:
I had same problem in my Razor MVC Application throwing exceptions while ajax calls made when session timed out.
The way I have managed to get this issue sorted is by monitoring each ajax requests by using a simple light weight Action Method (RAZOR MVC) returning a bool variable whether the Request is Authenticated or not. Please find the code below..
Layout/Master Page / Script file:
<script>
var AuthenticationUrl = '/Home/GetRequestAuthentication';
var RedirectUrl = '/Account/Logon';
function SetAuthenticationURL(url) {
AuthenticationUrl = url;
}
function RedirectToLoginPage() {
window.location = RedirectUrl;
}
$(document).ajaxStart(function () {
$.ajax({
url: AuthenticationUrl,
type: "GET",
success: function (result) {
if (result == false) {
alert("Your Session has expired.Please wait while redirecting you to login page.");
setTimeout('RedirectToLoginPage()', 1000);
}
},
error: function (data) { debugger; }
});
})
Then in Home Controller/Server side you need a method to verify the request and return the boolean variable..
public ActionResult GetAuthentication ( )
{
return Json(Request.IsAuthenticated, JsonRequestBehavior.AllowGet);
}
This will validate each ajax request and if the session got expired for any ajax request, it will alert the user with a message and redirect the user to the login page.
I would also suggest not to use standard Alert to Alert. User some Tool tip kind of formatted div Alerts. Standard JS Alerts might force the user to click OK before redirection.
Hope it helps.. :)
Thanks,
Riyaz
Finally, I ended up following.
public class IsAuthorizedAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var sessions = filterContext.HttpContext.Session;
if (sessions["User"] != null)
{
return;
}
else
{
filterContext.Result = new JsonResult
{
Data = new
{
status = "401"
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
//xhr status code 401 to redirect
filterContext.HttpContext.Response.StatusCode = 401;
return;
}
}
var session = filterContext.HttpContext.Session;
if (session["User"] != null)
return;
//Redirect to login page.
var redirectTarget = new RouteValueDictionary { { "action", "LogOn" }, { "controller", "Account" } };
filterContext.Result = new RedirectToRouteResult(redirectTarget);
}
}
Handling client side
<script type="text/javascript">
$(document).ajaxComplete(
function (event, xhr, settings) {
if (xhr.status == 401) {
window.location.href = "/Account/LogOn";
}
});
</script>
you can set session time out expire warning some thing like ....
<script type="text/javascript">
//get a hold of the timers
var iddleTimeoutWarning = null;
var iddleTimeout = null;
//this function will automatically be called by ASP.NET AJAX when page is loaded and partial postbacks complete
function pageLoad() {
//clear out any old timers from previous postbacks
if (iddleTimeoutWarning != null)
clearTimeout(iddleTimeoutWarning);
if (iddleTimeout != null)
clearTimeout(iddleTimeout);
//read time from web.config
var millisecTimeOutWarning = <%= int.Parse(System.Configuration.ConfigurationManager.AppSettings["SessionTimeoutWarning"]) * 60 * 1000 %>;
var millisecTimeOut = <%= int.Parse(System.Configuration.ConfigurationManager.AppSettings["SessionTimeout"]) * 60 * 1000 %>;
//set a timeout to display warning if user has been inactive
iddleTimeoutWarning = setTimeout("DisplayIddleWarning()", millisecTimeOutWarning);
iddleTimeout = setTimeout("TimeoutPage()", millisecTimeOut);
}
function DisplayIddleWarning() {
alert("Your session is about to expire due to inactivity.");
}
function TimeoutPage() {
//refresh page for this sample, we could redirect to another page that has code to clear out session variables
location.reload();
}
4xx are HTTP error status codes and would cause jquery to execute the onFailure callback.
Also, beware of using 3xx for redirects when you want to process the payload. Internet Explorer, in my experience, just does a redirect (without looking at the payload) when a 3xx status code is returned.
I'd say, throw a 403 and handle the situation. To the client 403 implies the resource access is forbidden. There can be multiple reasons, which is OK I guess.
For those using a ScriptManager, you can easily check for ajax request and then redirect with the following code:
private void AjaxRedirect(string url)
{
Response.StatusCode = 200;
Response.RedirectLocation = url;
Response.Write("<html></html>");
Response.End();
}
Then check for request type and redirect accordingly (using routes here):
if (ScriptManager.GetCurrent(Page).IsInAsyncPostBack)
{
var redirectUrl = RouteTable.Routes.GetVirtualPath(null, "Default", null).VirtualPath;
AjaxRedirect(redirectUrl);
}
else
{
Response.RedirectToRoute("Default");
}
The "Default" route is a route defined in the routes collection:
routes.MapPageRouteWithName("Default", "", "~/default.aspx");
If you prefer, instead of using ScriptManager for ajax request check, you can use:
if (Request.Headers["X-Requested-With"] == "XMLHttpRequest") {
code here...
}