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.
Related
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/
I have added a controller to my project named UserManager (automatically generated from the ado.net framework)
When I start the application, attempts to navigate to http://server/UserManager/ are met with a 404 error, but if I go to http://server/UserManager/Index the action is found and executes properly.
Is this a case of the controller not being called or is it just not treating index as the default action. Where are these properties set?
UPDATE
It seems that the problem derived from the fact that the default route is set to
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Permits", action = "ListApplications", id = UrlParameter.Optional }
This conflicts with the naming scheme for Usermanager (where the default is Index)
I struggled with ohow to add alternate routes that provided for default actions, but eventually figured out that the order of route addition determines which route takes the request (the earlier the route is added, the more chances it has to meet the criteria.)
Thanks
You need to ensure that the default route mapping specifies "Index" as the default action in your global.asax file.
Check that you have the following setting in your global.asax file:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
IN REPLY TO YOUR COMMENT:
Only by way of adding new route mappings. You also need to be aware that the first matching route mapping will be applied, so the order you specify the mappings in Global.asax is crucial.
For example, we wanted our FAQ controller to work with a URL http://domain/faq/{id} without the action specified in the URL, so we declared the following mapping before the default:
routes.MapRoute("Faq", "Faq/{id}", new { controller = "Faq", action = "Answer" });
In Global.asax.cs, check the default route is set up:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}", new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional}
);
Also, check that the controller is called UserManagerController, and derives from Controller
I have a problem. I have a area in MVC 3 called Page that works as it should.
I just added a new Area called Media and now I get "the resource cannot be found" for that new area. I am going crazy, since it looks exactly like the PageArea that works.
Here is the MediaAreaRegistration.cs
public override string AreaName
{
get
{
return "Media";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Media_default",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
Here is my global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
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
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
I am trying to access via localhost/media/, but I am just getting "the resource cannot be found".
Any ideas?
Check the Namespace of the Controller;
In my case; the default route was:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
defaults: new {controller = "Home", action = "Index", AreaName="Admin", id = UrlParameter.Optional },
namespaces: new[] { "MyApp.Admin.Controllers"}
);
But when I was create the controller, the MVC automatically set "MyApp.WebUI.Areas.Admin.Controllers" as the namespace of the new Controller; I Changed the namespace to what I defined in default route as "MyApp.Admin.Controllers" and application works fine.
Typically, when you create an area, you will get a somewhat different default route than what is in global.asax. For example, I created a Media area in an MVC3 project, and the default route looks like this:
context.MapRoute(
"Media_default",
"Media/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Routes in areas are really no different than routes defined in your global asax, except that they look for controllers in a different namespace. Also, they are loaded before the routes in your global.asax. You can see this because in Application_Start, RegisterAllAreas is invoked before RegisterRoutes.
Typically, this is the URL schema for root controllers with routes defined in your global.asax:
base/ControllerAName/Action1Name
base/ControllerAName/Action2Name
base/ControllerBName/Action6Name
...and so on. This is the "convention" you get with MVC out of the box. Look closely, and you will see that this pattern matches the base route definition 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
);
On the other hand, the convention when you use areas is that your "conventional" URL schema will look like this:
base/AreaName/ControllerAName/Action1Name
base/AreaName/ControllerAName/Action2Name
base/AreaName/ControllerBName/Action6Name
Notice the difference? This is why your default route definition in the area registration looks like this: "Media/{controller}/{action}/{id}"
With all of this said, there is nothing stopping you from deviating from the conventions. It sounds like you want to have an area named Media, and a URL base/media that goes to some action method on some controller in the area. If that is correct, try this -- remembering to put your more specific route before the default route generated by MVC:
context.MapRoute(null,
"media",
new { action = "Index", controller = "Media" }
);
context.MapRoute(
"Media_default",
"Media/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
This means that MVC will match base/media to the Index action method on the MediaController in your Media area, since that route is defined first.
Also, when you create a new area, don't change any namespaces. This will only cause you problems.
Another tip is to not give route names to your routes. Notice how I passed null as the first argument. This is considered good practice -- accessing routes by name can get very messy.
I suggest you try starting a new project, or creating a new area, and trying these suggestions. Grasping routes coming from webforms can be tricky, but once you get a handle on it, I think you will find it superior to the URL-TO-FILE mapping in webforms.
In my case, someone added routes.Clear() in RouteConfig.cs, before any area ever existed. But now I added an area, this was erasing all its routes.
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.
I am using ASP.NET MVC3 and curious about how to make routes like /Account/Ajax/Action map to controller AccountAjaxController method Action
Is there any way to do so?
Already solved issue using following code in Global.asax.cs file:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional},
new[] {"MyProjectName.FrontEnd.Web.Logic.Controllers"}
);
routes.MapRoute(
"Ajax",
"Ajax/{controller}/{action}/{id}",
new[] {"MyProjectName.FrontEnd.Web.Logic.Controllers.Ajax"}
);
One way that I've done this is with RouteCollection.MapRoute(). See http://msdn.microsoft.com/en-us/library/dd470521.aspx. You can do all kinds of stuff with routes.
In the code below I would typically call this from my global.asax.cs Application_Start():
RouteCollection routes = RouteTable.Routes;
routes.MapRoute(
"ArbitraryRouteName", // Route name
"Account/Ajax/Action/", // URL with parameters
new
{
controller = "AccountAjax",
action = "Action"
}, // Parameter defaults
new
{
}
);
There are many ways to use this in order to generate links. You can use Html.RouteLink() in your views as an example. I believe that you can also call Html.ActionLink("link text", "AccountAjax", "Action"). I think that providing there is only one Route mapped to your controller and action name, ASP.NET MVC automatically figures out the proper URL to generate from your route mappings.
See http://msdn.microsoft.com/en-us/library/dd492585.aspx for an example of the RouteLink extension method.