your application has redirected loops in MVC - asp.net-mvc

After writing code in global.asax this error ocured. If i keep a break point to check it was firing and spinning and eventually browser outcomes with the above responce["Your application has redirected loops"].
`
public class SessionExpireAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check sessions here
if (HttpContext.Current.Session["username"] == null)
{
filterContext.Result = new RedirectResult("~/Account/Login");
return;
}
base.OnActionExecuting(filterContext);
}
}`
Really funny but why this stupid error occuring again and again.Any Idea?

Remove this ActionFilter from AccountController

When you redirect to "~/Account/Login" the code of OnActionExecuting will be called again so HttpContext.Current.Session["username"] == null is true and you have your redirect loop.
So, you need other condition for check this

I'm sorry, i didn't read your question properly
public class SessionExpireAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check sessions here
if (HttpContext.Current.Session["username"] == null)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary {
{ "Controller", "Accounts" },
{ "Action", "Login" }
});
}
base.OnActionExecuting(filterContext);
}
}
Hope this works.

Related

Redirect to a view Action Filter Attribute

How can I redirect logged in users (in every page) to a view asking them to complete their info?
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (userIsLoggedIn)
{
filterContext.Result = new RedirectResult(userInfoView);
}
base.OnActionExecuting(filterContext);
}
You can't redirect to a view, you need to redirect to an action method and that action method would return the view:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (userIsLoggedIn)
{
filterContext.Result = new RedirectToAction("UserInfoActionName", "UserInfoControllerName");
}
base.OnActionExecuting(filterContext);
}
This blog explains exactly the same problem.
RedirectToAction is avaible in MVC Core. I archived this as follows in MVC 4:
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!condition)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary{ { "controller", "YourController" },
{ "action", "YourAction" }
});
}
}
This will redirect you to the given action then to the relevant view.

asp.net mvc redirect to login on session expiry

I am trying to do a simple redirect to login page if session expires in asp.net mvc 4.5. I am trying it as follows.
Global.asax
protected void Session_OnEnd(object sender, EventArgs e)
{
Response.RedirectToRoute("Default"); //default is route
}
but here null exception comes and response object is not found. I have seen this post but could not figure out as it is pretty broad.
UPDATE
I have tried applying filter as follows now it does not crash but also does not redirect to error page.
SessionTimeoutAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
if (HttpContext.Current.Session["SchoolCode"] == null)
{
filterContext.Result = new RedirectResult("~/Views/Shared/Error");
return;
}
base.OnActionExecuting(filterContext);
}
Added Attribute to Controller class
[SessionTimeout]
public class MapsController : Controller{}
Why doesnt it redirect?
I had to change my code a little
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
if (HttpContext.Current.Session["SchoolCode"] == null)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(
new { action = "Login", controller = "Account" }));
//return;
}
base.OnActionExecuting(filterContext);
}
ignore Session_OnEnd code its no use.

Trigger authorization validation manually

I've a custom AuthorizeAttribute in my website. It has some logic about the Result created for unathorized requests.
In some cases, I want to trigger its validation manually*. I don't know if its possible. As I haven't found how to do that, I thought that I could extract the logic to get the Result to a diferrent method, and call it when I want. But then I don't know how to execute the ActionResult (outside de controllers).
How can I do to manually execute authorize validation? If not possible, how can I do to execute an ActionResult outside a controller?
*I need to trigger it manually because some request may pass the validation (because the session is created) and then, when accessing my services, found that the session was closed by someone else. I wouldn't like to add a call to the services in OnAuthorization to reduce services calls.
I'm not sure if its the best, but I've found a way to get it working (still listening for better answers).
When I call the services and notice that the work session has expired, all I do is removing the active user in the web session.
My custom authorize attribute also implements IResultFilter and IExceptionFilter.
In both OnResultExecuted and OnException I validate the active user once more. If the session was removed, then apply the same ActionResult that I would apply in OnAuthorization.
Here is the final class:
public class CustomAuthorizeAttribute : AuthorizeAttribute, IResultFilter, IExceptionFilter
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
ActionResult result = Validate(filterContext.HttpContext);
if (result != null)
filterContext.Result = result;
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
ActionResult result = Validate(filterContext.HttpContext);
if (result != null)
filterContext.Result = result;
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
}
public void OnException(ExceptionContext filterContext)
{
ActionResult result = Validate(filterContext.HttpContext);
if (result != null)
{
filterContext.Result = result;
filterContext.ExceptionHandled = true;
}
}
public static ActionResult Validate(HttpContextBase httpContext)
{
if (UserActiveInSession)
return null;
// Different rules to build an ActionResult for this specific case.
}
}
I did not get Diego answer's, But Just simply answering the title, I got it to work like that, You can use it as attribute on controllers actions and also trigger it manually at any place in C# or in Razor views.
namespace SomeNameSpace
{
public class CustomAuthorizeAttributeMVC : AuthorizeAttribute
{
private readonly string[] rolesParams;
public CustomAuthorizeAttributeMVC(params string[] roles)
{
this.rolesParams = roles;
}
public bool IsAuthorized { get {
//Do your authorization logic here and return true if the current user has permission/role for the passed "rolesParams"
string[] allowedRoles = new string[] {"role 1", "role 2", "role 3"};
return allowedRoles.Intersect(rolesParams).Any(); //for the example
}
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return this.IsAuthorized;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//...
}
}
public class AuthorizeHelper
{
public static bool HasPermission(params string[] roles)
{
return new CustomAuthorizeAttributeMVC(roles).IsAuthorized;
}
}
}
Usage example:
[CustomAuthorizeAttributeMVC("role 2")]
public ActionResult SomeAction()
{
return Content("Authorized !");
}
public ActionResult SomeOtherAction()
{
if(AuthorizeHelper.HasPermission("role 2"))
{
return Content("Authorized !");
}
return Content("401 Not Authorized !");
}
And as said, it can be used in Razor views by calling it normally
#if(AuthorizeHelper.HasPermission("role 2")) {
//...
}
Thanks

Referer null help me

Good morning guys. I'm having the following problem. I created an override method to validate referer:
public class VerifyOutUrlReferer : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext != null)
{
if (filterContext.HttpContext.Request.UrlReferrer == null)
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{"controller", "Validate"},
{"action", "Referer"},
{"code", 123ER}
});
}
}
}
[VerifyOutUrlReferer]
public ActionResult GeneralError(string errorCode)
{
return View();
}
and add it on top of the method...
I try to call this method by screen controller that validates 404 error, so that does not always redirects to her because the referer is empty. Could someone help me how I can call this screen by controllers.

How to pass ModelErrors along with redirect?

ASP.NET MVC 2.0
I'm doing Post-Redirect-Get, if I get errors on post, I need to include ModelErrors along for the ride to along -Redirect-Get route.
I send it through 'TempData':
TempData["modelErors"] =
ModelState.
Where(item => item.Value.Errors.Count > 0).
ToDictionary(
item => item.Key,
item => item.Value.Errors.Select(error=>error.ErrorMessage).ToList()
);
And then reinsert it into a ModelState:
if (TempData.ContainsKey("modelErors")) {
foreach (var errors in (IDictionary<string,IList<string>>) TempData["modelErors"]) {
foreach (var error in errors.Value) {
ModelState.AddModelError(errors.Key, error);
}
}
}
Is there a better way?
You should really only PRG after a successful post. Otherwise it's fine to return from the post if there's an error.
Otherwise you need to use cookies, session or request variables to store that information for the next request.
In ASP.NET MVC2 by default I think TempData uses Session state to store the information for the next request.
I think that the most cleaner solution was to use ActionFilterAttribute like this :
public class RedirectErrorAttribute : ActionFilterAttribute
{
#region Methods & Function
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Controller.TempData.ContainsKey("modelErrors"))
{
foreach (var errors in (Dictionary<string, List<string>>)filterContext.Controller.TempData["modelErrors"])
foreach (var error in errors.Value)
filterContext.Controller.ViewData.ModelState.AddModelError(errors.Key, error);
}
base.OnActionExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Controller.ViewData.ModelState.Values.Any(x => x.Errors.Count > 0))
{
if (filterContext.Controller.TempData.ContainsKey("modelErrors"))
filterContext.Controller.TempData.Remove("modelErrors");
else
{
filterContext.Controller.TempData["modelErrors"] =
filterContext.Controller.ViewData.ModelState.
Where(item => item.Value.Errors.Count > 0).
ToDictionary(
item => item.Key,
item => item.Value.Errors.Select(error => error.ErrorMessage).ToList()
);
filterContext.Controller.TempData.Keep("modelErrors");
}
}
base.OnResultExecuted(filterContext);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
}
#endregion
}
After you just have to put your attribute on the top of the action that throw the error and the action that received the error like this :
[RedirectError]
public ActionResult Delete(Guid id)
{
[RedirectError]
public ActionResult Get(Guid id)
{
And that works like a charm with clean manageable code.
Hope this Help!
Julien

Resources