MVC3 Area +Authorize attribute + Role strange issue - asp.net-mvc-3

I really don't know what title should I use to describe my problem. To simplify my problem. Here is my test. I create a mvc3 site from scratch. I then add area called "admin". Inside admin, I have a controller named "Search" and has "Authorize" attribute decorated. I then changed my Global.ascx.cs route setting to append my controller namespace. Now I start my test.
Question 1
When I am accessing to http://localhost:xxx/Search page, it redirects me back to /Account/Logon page, it makes me confuse first, why it redirects me to logon page? it shouldn't reach to Admin search controller at all as I understand. If I removed the Authorize attribute, it display the yellow screen said can't find the view as I expected.
Question 2
If I add Authorize attribute with role, e.g. (Roles="Admin"), then I try access to Search page again, no matter login succeed or not, I always get redirect back to logon page. Why it doesn't give me the yellow screen, coz I am trying to request the search controller index view in the main site not the admin area's one. quite confuse.
I am a newbie in MVC development, can someone give me a solution regarding to my problem?
Thanks
Global.ascx.cs
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 },
new string[]{"TestAreaRouting.Controllers"}
);
}

You could constrain the default controller factory to look only inside the specified namespace for controllers in the RegisterRoutes method of Global.asax by setting the UseNamespaceFallback data token to false:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "TestAreaRouting.Controllers" }
).DataTokens["UseNamespaceFallback"] = false;
}
If you don't do this when you request /search the admin area route doesn't match because the url doesn't start with the Admin prefix.
So it is the default route that matches. The default controller factory starts scanning the assembly for a class called SearchController that derives from Controller and since it finds one it instantiates it and uses it to serve the request. Obviously it doesn't find a corresponding Index view because it looks in ~/Views/Search/Index.cshtml which obviously doesn't exist. The actual view is located in the area.
Now that we have constrained the controllers to their respective locations you could decorate them with the Authorize attribute and it should behave consistently.

Related

.NET MVC Routing works, except for one piece

Little help here and advice.
Working on my first MVC application and I've got an entity of Students setup.
Student Controller and views with basic CRUD capabilities.
mysite.com/Student gets me there.
Now I want to add Payments, so I've added a Payments controller and views with basic crud.
that gives me mysite.com/Payments
I want payments to go a URL that looks like: mysite.com/Student/Payments
So I researched URL routing and (I think) I had it backwards for a long time as nothing seemed to work. But now, I've created this additional Route:
routes.MapRoute(
"Payments",
"Student/Payments/{action}/{id}",
new { Controller = "Payments", action = "Index", id = UrlParameter.Optional }
);
And now it all seems to work properly. When I send an ActionLink to any action in the Payment controller, the URL is correct. For example: www.mysite.com/Student/Payments/Edit/5 comes up as the URL.
The problem I'm having is that Payments is still a base URL route. So I can also get to payments by going to www.mysite.com/Payments
How do I "remove" that route, so that mysite.com/Payments is not valid? Or am I doing this all ass-backwards in some way?
Any help appreciated.
Your kind of thinking about it the wring way around. The mapping configuration just supplies a hierachical list of rule to specify where a particular url's code lives.
So when you say it's still hitting mysite.com/Payments. That's because it's hitting the default rule in your Global.asax
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
);
You could remove this but then no default rules will work.
or you can add an ignore rule. In your case something like
routes.IgnoreRoute("Payments/{action}/{id}");
make sure you put this above the default rule.
You need to use overload of MapRoute method for your default route i.e.:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index" },
new { controller = ""}); //there constraints for controller goes
Look at this blog post about creating custom constraints, there is example for "not equals"

MVC3 Url Routing to create member area

I would like to create a member area on my site with the following URL patterns:
Pattern for logged out user:
domain.com
domain.com/About
domain.com/Blog
domain.com/Blog/1 (where 1 is the post ID)
But I also have a member area where I prefix the Url with Member like this:
domain.com/Member/MyProfile
domain.com/Member/MySettings
This seems simple, but I can't see an obvious way to make routing rules for this. I have:
routes.MapRoute(
"Member", // Route name
"Member/{controller}/{action}/{id}", // URL with parameters
new { controller = "Task", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
This works great for the member when you are logged in, but unfortunately the first rule also matches the logged out view and Url.Action("Blog", "Home") produces a Url that looks like this:
domain.com/Member/Home/Blog
How do I tell Url.Action that it must form Urls with the default rule outside the member area?
You could use a real MVC area instead of trying to simulate one. There's also a video you might checkout. The idea is that you leave your default route definition in Global.asax and then add a Member area to your site which will have a separate route configuration.

ASP.NET MVC3 sample project removing home folder

I'm using the ASP.NET MVC3 sample project and would like to have new links added to the page that go directly to the root url
So instead of mydomain.com/Home/About it would do mydomain/About.
This page suggests adding a new route. http://weblogs.asp.net/gunnarpeipman/archive/2011/04/17/asp-net-mvc-defining-short-urls-for-root-level-pages.aspx
Is there another way? Say I have 5 pages that will be on the root do I have to add a special route for each one?
Under the assumption that you are looking to do a bunch of single path requests/respones, and not just redirect home controller actions, then this is an option.
The link you provide is one way to do that. The other is to create 5 controllers using the default route. I'm not sure if I would suggest either is better (due to a lack of what your 5 paths actually are), but they both produce the same out come. If your default route looks like:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
It's basically stating that the default controller is home and the default action is index. These values are not mutually inclusive, meaning that neither required the other in order to be a default value.
Thus you could do:
website.com/about with
public AboutController
{
public ActionResult index()
{
return this.View();
}
}
and/or website.com/people with
public PeopleController
{
public ActionResult index()
{
return this.View();
}
}

Hierarchies in MVC3

Im working my way though an ASP.NET MVC tutorial and couldnt find the answer im looking for.
I understand that each controller class in the 'Controller' root folder is mapped to a Url, so:
****Controller Folder****
|- StoreController.cs
Maps to $url/Store
However, If I wish to creater a 'subfolder'
I.e. a Controller class located for $url/Store/Testing I cant seem to see how I go about it.
I tried deriving a class from StoreController.cs, but that didnt work.
URLs do not necessarily correspond to MVC application internal folder structure. You can use MVC routing tables to conceal the internal structure and redirect specific URLs to any controllers/actions you want. For example, you can create a TestingController.cs class in the Controllers folder and use this route in Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Store-Testing", // Route name
"Store/Testing/{action}/{id}", // URL with parameters
new { controller = "Testing", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
In this case, a request to http://[domain]/Store/Testing will be handled by TestingController.
That url would with the default route point to an action called Testing, within the Store controller.
You can however create your own custom routes in your global.asax file.

Incorrect Routing is ASP.NET MVC

I don't know why I have such problems with ASP.NET MVC routing. I wish there was a tool that showed me which routes I had currently setup. Regardless,
In my global.asax.cs file I have the following:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"SignUp", // Route name
"account/{controller}/{action}", // URL with parameters
new { controller = "Home", action = "Register" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
I have the following defined in HomeController.cs
public ActionResult Register()
{
return View();
}
I was expecting to be able to access this page by visiting /account/register in my browser. However, I continue to get a 404. What am I doing wrong?
/Account/Register matches your first route.
The word Register is matched to the {controller}, so it looks for a controller named RegisterController.
replace
routes.MapRoute(
"SignUp", // Route name
"account/{controller}/{action}", // URL with parameters
new { controller = "Home", action = "Register" } // Parameter defaults
);
with
routes.MapRoute(
"SignUp", // Route name
"account/{action}", // URL with parameters
new { controller = "Home" } // Parameter defaults
);
This will mean /account/register will route to the Register action on the Home controller. It will also mean that action links and other links you generate via #Html.ActionLink("Register", "Register", "Home") will generate the URL /account/register
Think of the 'URL with paramters' as a pattern that the URL will be matched against.
The problem with your original route map is that it is looking for a URL like this /account/controllername/actionname. So, when you go /account/register - it is taking register as the controller name, and taking the default action name (in this case register) - and as the 'register' action does not exist in the 'register' controller - you are getting a 404.
UPDATED
I updated my suggested route as per Robert's comments.
It is also worth noting, as Robert states, that this whole thing could be made more simple by making a 'Account' controller, and moving the 'Register ' action there. Then you could delete the 'SignUp' route, and just use default routing. If you thought about it, you'd agree that this would be a better place for a 'Register' action than the 'Home' controller.
Try using this nugget package http://nuget.org/packages/Glimpse.Mvc3
You can find more info about glimpse on http://getglimpse.com/

Resources