I need to have a parameter as part of my ASP MVC URL before Controller and Action:
http://www.mydomain.com/company1/Home
or
http://www.mydomain.com/company1/Clients/Detail/1
(Ideally I would like to have this as a sub-domain like this: http://company1.mydomain.com/Clients/Detail/1 so any answers solving this one is also appreciated)
I call this parameter Account. I tried adding something like this to the routing map:
"{account}/{controller}/{action}/{id}" but it gives me a 404 error when trying something like http://www.mydomain.com/company1/Home
Here is the RegisterRoutes in Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("TestRoute", "{account}/{controller}/{action}/{id}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
Is there anything special I have to do when organising my Views folder or Controller actions?
Your error sounds like you are not giving a default for action in your route defaults.
Related
I've reorganized my project into a more logical hierarchy:
-Controllers
-Accounts
-CustomersController
-Setup
-SystemDefaultsController
-SettingsController
-HomeController
At the moment, I'm just trying to set up my URLs to match this structure. So valid example URLs would be:
localhost:1234/Home/Index
localhost:1234/Setup/SystemDefaults/Index
localhost:1234/Setup/Settings/Index
localhost:1234/CustomerAccounts/Index
So I added a route on top of the default route in RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcAttributeRoutes();
//AreaRegistration.RegisterAllAreas();
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Setup",
url: "Setup/{controller}/{action}/{id}",
defaults: new { controller = "Setup", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "MVCWeb.Controllers.Setup" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "MVCWeb.Controllers" }
);
}
This does make the above URLs work, but it has no constraints so these URLs work when I want them to be invalid:
localhost:1234/Setup/CustomerAccounts/Index
localhost:1234/SystemDefaults/Index
Additionally, since the Setup route matches everything, if I do either of these:
#Html.ActionLink("Customer Accounts", "Index", "CustomerAccounts")
#Url.Action("Index", "CustomerAccounts")
It generates the URL as /Setup/CustomerAccounts/Index instead of /CustomerAccounts/Index.
Is there a way to do accomplish this without using an Area while still using {controller} in the route URL? Or would I have to add a route specifically for each controller under Setup?
Have you ever evaluated Attribute Routing in MVC 5? It seems like you're starting a new project, so this could be a good new start. With the [RoutePrefix] attribute, you could probably enforce what you want to achieve easily:
[RoutePrefix("accounts")]
public class CustomersController : Controller
{
// ...
}
We don't use Attribute Routing yet so I can't speak from own experience but it looks very flexible and promising.
UPDATE
I created a GIST for you where I explain how you could validate your Attributes, not during compile time, but with Unit Tests. This is a simple code snipped designed for MS Test. The validation possibilities are very broad.
Custom Logic we might add to a custom RoutePrefixAttribute? For example, the RoutePrefixAttribute allows a string as a parameter. You could rewrite it to allow only a specific Enum as parameter, which lists only possible values, and internally set the Prefix string.
Is there a simple catch-all way to ensure only rewritten URLs can invoke a controller?
For example, if we have a URL www.somesite.com/about pointing to action "About" in controller "Shared", can it be ensured that any requests to www.somesite.com/shared/about end up at the rewritten URL, in this case www.somesite.com/about?
In other words, the user should not be able to just type /controller/action without being redirected to the rewritten URL.
However, we don't want to actively check and redirect but were hoping for some built-in function of MVC. The only suggestions I found along those lines were ChildActionOnly and HttpPost attributes, but they don't seem to be the answer (normal links don't work).
As mentioned, we're looking for something simple, more or less built-in - if it doesn't exist then so be it...
The built-in way of blocking routes is to use IgnoreRoute. It short-circuits routing and always makes the path throw a 404 not found.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Ignore /Home/About
routes.IgnoreRoute("Home/About");
// Register /About
routes.MapRoute(
name: "About",
url: "About",
defaults: new { controller = "Home", action = "About" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Note that under the covers, it uses the StopRoutingHandler, which can be used (as a replacement for MvcRouteHandler) in any custom Route or RouteBase implementation to make more dynamic ignore rules than this.
NOTE: It is extremely important that IgnoreRoute is registered before the route you want to ignore in the route table.
Example : My User will enter www.xyz.com/Promo/PROMO123
where "PROMO123" is value, which i require.
above code produces error :
Server Error in '/' Application.
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.
However
www.xyz.com/Promo/Index/PROMO123 will work properly,
but i dont want this.
How can i archive this
www.xyz.com/Promo/PROMO123
Have you tried Routing?
Such as
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//Don't forget to add this before default one.
routes.MapRoute(
name: "PromoRoute",
url: "{controller}/{myString}",
defaults: new { controller = "Promo", action = "Index", myString = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
You need to define a route pattern for this.
If you want this to work application wide, then you will need to change the default route. But I would suggest simply adding a specific route for this controller, in addition to the default route, because you probably don't want to override the default MVC routing for the whole app or you will lose the ability to use multiple actions per controller.
See your RouteConfig, try this route (MVC pre-5):
routes.MapRoute("myRoute", "PromoRoute/{id}",
new {controller="PromoRoute", action = "Index"});
With MVC5 you can add this directly to your action assuming you've enabled attribute routes:
[Route("PromoRoute/{id}")]
public ActionResult Index(string id) {
}
I've been trawling through 1000s of questions and blogs and still don't fully understand dam routing!
Along the lines of Scott Hanselman's blog I am trying to route a certain call to a .GIF to a custom HttpHandler while the rest of the MVC4 site behaves normally. I'm 90% of the way there.
So in the my RouteConfig I have
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("AnalyticsRoute", new Route("analytics/a.gif", new AnalyticsRouteHandler()));
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.RouteExistingFiles = true;
}
and in my web.config I have
<handlers>
...
<add name="analytics" verb="*" path="analytics/a.gif" type="Lms.Analytics.AnalyticsHandler, Lms.Analytics" preCondition="managedHandler" />
</handlers>
Now this way, http://mysite.com/analytics/a.gif routes correctly and all is happy, however all my ActionLinks are resolving as http://mysite.com/analytics/a.gif?action=Index&controller=Category
If I reverse the order in the RouteConfig i.e.
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 });
routes.Add("AnalyticsRoute", new Route("analytics/a.gif", new AnalyticsRouteHandler()));
routes.RouteExistingFiles = true;
}
All the links resolve just fine, but a call to http://mysite.com/analytics/a.gif results in a 404 error?
I must be doing something stupid and just can't see it?!
Thanks in advance
After finally coming across a similar post, I cracked it. The post was why is the httphandler not running
You need to ignore the path to the file you want the HttpHandler to handle
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("analytics/a.gif");
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.RouteExistingFiles = true;
}
The problem was when I added the web.config and removed the Route.Add I got a 404. I guess the Routing engine was over ruling the Handler.
What you need to do is to create your own custom Route class.
In this class you must override the GetVirtualPath method (on MSDN), which will examine the route data, and generate the right Url. Implement it so that it returns null if your special Url it's not in the provided RequestContext.
What is going on now in your app is that you're using the standard Route class which treat the controller and action in the RouteValue dictionary as overflow paramters, so they're added to the created url.
When you add the route to the route collection use your custom class instead of the default Route class.
More explanation: when you use any method like Url.Action to create a Url, RouteCollection.GetVirtualPath is called. And this method calls the GetVirtualPath of every registered Route, until one of them returns a value different from null (the Url string).
As you're not providing your own Route class, the "standard" Route class is being used, and returning the undesired Url. If you create your custom Route class with you own GetVirtualPath implementation you'll return the desired Url.
According to Hanselman's article, you don't want to add a route for your image, you just want to set up the handler in your web.config. Have you tried removing your AnalyticsRoute and see if it works? You may also need to add an ignore route to keep MVC from trying to handle the request.
I haven't used it, but I've heard RouteMagic, written by Phil Haack, is great at troubleshooting route issues.
I'm trying out ASP.NET MVC routing and have of course stumbled across a problem. I have a section, /Admin/Pages/, and this is also accessible through /Pages/, which it shouldn't. What could I be missing?
The routing code in global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Pages", // Route name
"Admin/Pages/{action}/{id}", // URL with parameters
// Parameter defaults
new { controller = "Pages", action = "Index", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
// Parameter defaults
new { controller = "Home", action = "Index", id = "" }
);
}
Thanks!
I'd suggest adding an explicit route for /Pages/ at the beginning.
The problem is that it's being handled by the Default route and deriving:
controller = "Pages"
action = "Index"
id = ""
which are exactly the same as the parameters for your Admin route.
For routing issues like this, you should try out my Route Debugger assembly (use only in testing). It can help figure out these types of issues.
P.S. If you're trying to secure the Pages controller, make sure to use the [Authorize] attribute. Don't just rely on URL authorization.
You could add a constraint to the default rule so that the {Controller} tag cannot be "Pages".
You have in you first route {action} token/parameter which gets in conflict with setting of default action. Try changing parameter name in your route, or remove default action name.