AuthorizeAttribute not working if URL has query string? - asp.net-mvc-3

In an ASP.NET MVC3 web application, an entire controller has an [Authorize] attribute attached to it. So if the user is not logged in or the session expired, they get redirected to the login page. This is working...sometimes. The URLs in the "works" list below correctly redirect to the login page; the URLs in the "does not work" list instead show the IIS 401 error screen - they do not redirect to the login page.
Works
http://x.y.z/MyController/MyAction
http://x.y.z/MyController/MyAction/123
http://x.y.z/MyController/MyAction/123?X=Y
Does Not Work
http://x.y.z/MyController/MyAction/123?ReturnUrl=
http://x.y.z/MyController/MyAction/123?ReturnUrl=XYZ
The model for the MyAction action has a public string ReturnUrl { get; set; } in its base class. It also has other properties, but adding those to the query string does not affect the login redirection. It seems to be only the ReturnUrl parameter.
I'm not sure what else to look into. Any ideas why the ReturnUrl parameters would be causing trouble?
Routes
routes.MapRoute("Default-Title-ID", "{Controller}/{Action}/{Title}_{ID}", namespaces);
routes.MapRoute("Default-ID", "{Controller}/{Action}/{ID}", namespaces);
routes.MapRoute("Default", "{Controller}/{Action}", new { Controller = "Home", Action = "Index" }, namespaces);
routes.MapPageRoute("Reports-View", "ViewReport_{ID}", "~/Views/Reports/View.aspx");
Working Example (Well, not working, but illustrates the problem.)
Download the solution here: https://docs.google.com/file/d/0B4o6vqgNLpvbeVo4bVdKZWFMcEE/edit?usp=sharing
And then try to visit:
http://your.local.host/Test/TestMe?ReturnUrl= - you will not be redirected to the login page.
http://your.local.host/Test/TestMe - you will be redirected to the login page.

I wanted to post this as a comment, but I is too long. I needed a dynamic redirect for one of my apps, and used the following solution (it uses the controller that called it instead of the static URL in web.config). When testing this with your example, it fixes the issue. But I can not figure out why. Maybe it will lead you to the right path or someone else can clarify.
using System.Web.Mvc;
using System.Web.Routing;
namespace MvcApplication1.App_Start
{
public class LoginRequiredAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{ "controller", filterContext.RouteData.Values[ "controller" ] },
{ "action", "Login" },
{ "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
});
}
}
}
}
Then just change the action to use the new attribute:
[LoginRequired]
public ActionResult TestMe()

Related

Server Error in '/' Application MVC3

im not sure what i messed up, but i just keep getting the following error upon f5.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /
The following is my route, totally default and no changes.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
I have checked my project properties -> web tab, "Specific page" has nth. My project has Home folder with Index page.
Other pages are working only after manually inputting URL. For eg: http://localhost:21183/store/search
Thanks
Things to check:
You have a public class named HomeController that derives from Controller.
This HomeController class has a public Index action.
You have a corresponding view ~/Views/Home/Index.cshtml
You are testing this inside a web server which supports extensionless urls. For example this won't work out of the box in IIS 6.0.
Controller:
public class HomeController: Controller
{
public ActionResult Index()
{
return View();
}
}

Recommended API design with ASP.NET MVC3

I'm working with ASP.NET MVC 3. I'm kind of new to it. I think I'm starting to get the hang of it. But there is something that I'm trying to do, that I think makes sense, but maybe I'm wrong.
I'm trying to create an API around Order objects in my database. In order to get all of the orders in the system, I was going to expose an API that looks like the following:
/orders/
In cases where I wanted to get a specific Order, I would simply append an ID. In other words, the URL would look like this:
/orders/12345
In an effort to accomplish this, I created the following controller:
public class OrdersController : Controller
{
// GET: /Orders/
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
string result = "list of orders";
return Json(result, JsonRequestBehavior.AllowGet);
}
//
// GET: /Orders/{orderID}
public ActionResult Index(int id)
{
string result = "order:" + id;
return Json(result, JsonRequestBehavior.AllowGet);
}
}
In my AreaRegistration class, I have the following:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"OrderList",
"{controller}/{action}",
new { action = "Index", controller="Orders" }
);
context.MapRoute(
"Order",
"{controller}/{action}/{id}",
new { action = "Index", controller = "Orders" }
);
}
When I attempted to access "/orders/", via the browser address bar, I get the JSON like I would expect. However, if I attempt to access "/orders/12345", I receive a 404. What am I missing?
Thank you
You need to also define proper routes in global.asax or use the default route which looks like {controller}/{action}/{id} where controller is defaulted to "Home", action is defaulted to "Index" and id is optional.
So /orders works because you have defined controller (orders), default action (Index) and missing id (which doesn't matter as it is optional)
But when you try /orders/12345 then you have defined controller (orders), action (12345) and missing id
So to make this work with only the default route the request should be /orders/index/12345
edit: for registering area routes you should use AreaRegistration class

Building an MVC3 route that has two different parameters

Here's what I want the user to see when visiting the page:
www.mywebsite.com/verify/sergiotapia/ASD98H1D9H12D081HD
Where sergiotapia is a username from my database, and OUAHSDFUOHASDFOUAHSDF is a generated field within User table.
This is for email verification purposes.
How would the route for this type of URL be, and also how would the ActionMethod signature be?
Any suggestions?
routes.MapRoute(
"Verify",
"verify/{username}/{token}",
new { controller = "Verify", action = "Index" }
);
and the controller:
public class VerifyController: Controller
{
public ActionResult Index(string username, string token)
{
...
}
}

ASP.Net Mvc 3 Url.Action method uses parameter values from previous request

When Urls are autogenerated using the Url.Action helper, if a page contains a line similar to
#Url.Action("Edit","Student")
is expected to generate a url like domain/student/edit and its working as expected.
But if the requested url contains some parameters, like domain/student/edit/210, the above code uses these parameters from the previous request and generates something similar even though I've not provided any such parameter to the Action method.
In short, if the requested url contains any parameters, any auto generated links of the page (served for that request) will include those parameters as well no matter if I specify them or not in the Url.Action method.
What's going wrong?
Use Darin's answer from this similar question.
#Url.Action("Edit","Student", new { ID = "" })
Weird, can't seem to reproduce the problem:
public class HomeController : Controller
{
public ActionResult Index(string id)
{
return View();
}
public ActionResult About(string id)
{
return View();
}
}
and inside Index.cshtml:
#Url.Action("About", "Home")
Now when I request /home/index/123 the url helper generates /home/about as expected. No ghost parameters. So how does your scenario differs?
UPDATE:
Now that you have clarified your scenario it seems that you have the following:
public class HomeController : Controller
{
public ActionResult Index(string id)
{
return View();
}
}
and inside Index.cshtml you are trying to use:
#Url.Action("Index", "Home")
If you request /home/index/123 this generates /home/index/123 instead of the expected /home/index (or simply / taken into account default values).
This behavior is by design. If you want to change it you will have to write your own helper which ignores the current route data. Here's how it might look:
#UrlHelper.GenerateUrl(
"Default",
"index",
"home",
null,
Url.RouteCollection,
// That's the important part and it is where we kill the current RouteData
new RequestContext(Html.ViewContext.HttpContext, new RouteData()),
false
)
This will generate the proper url you were expecting. Of course this is ugly. I would recommend you encapsulating it into a reusable helper.
Use ActionLink overload that uses parameters and supply null
You could register custom route for this action for example:
routes.MapRoute("Domain_EditStudentDefault",
"student/edit",
new {
controller = MVC.Student.Name,
action = MVC.Student.ActionNames.Edit,
ID = UrlParameter.Optional
},
new object(),
new[] { "MySolution.Web.Controllers" }
);
you then could use url.RouteUrl("Domain_EditStudentDefault") url RouteUrl helper override with only routeName parameter which generates url without parameters.

ASP.NET MVC 3 basic routing question

I am using ASP.NET MVC 3 and following the tutorial here http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-cs.
I am working on the sign up functionality and trying to make use of routing. So the typical scenario is:
When the user wants to sign up, he would get taken to /Account/SignUp.
Upon succesful sign up, he then gets redirected to /Account/SignUp/Successful.
I thought it would be simple enough but the "Successful" parameter never gets passed in the SignUp method in the controller.
public ActionResult SignUp(string msg)
{
// Do some checks on whether msg is empty or not and then redirect to appropriate view
}
In global.aspx.cs I've got pretty much the vanilla routing:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
What am I failing to grasp here?
Your route parameter is called id, so:
public ActionResult SignUp(string id)
{
...
}
or change it to msg if you want:
"{controller}/{action}/{msg}"
Change the parameter from your method to id and create an get method for the /Account/SignUp action
public ActionResult SignUp()
{
//this is the initial SignUp method
}
[HttpPost]
public ActionResult SignUp(string id)
{
//User will be redirected to this method
}

Resources