I want to call controller's Default action. - asp.net-mvc

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) {
}

Related

ASP.NET MVC Routing to sub directories without area

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.

Use of rewritten URLs vs direct controller call

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.

MVC route attribute exclude id

I have Home controller and Details action which received int id parameter.
I want map "/" url to Home controller, Details action, id = 1.
Also I want map urls like "/st15" to Home controller, Details action, id = 15.
So I wrote following attributes
[Route("~/{id:int:min(1):max(1)=1}")]
[Route("st{id:int:min(2)}")]
public ActionResult Details(int id)
{...}
The problem is url "/1" is also mapping to this action, but I need 404 for it
I would recommend leveraging the RouteConfig.cs file that is created with default MVC projects in VS2012.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Details",
url: "/st{id}",
defaults: { controller = "Home", action = "Details", id = "1" }
);
routes.MapRoute(
name: "Default",
url: "/",
defaults: new { controller = "Home", action = "Details", id = "1" }
);
}
This will try to match urls to those two designated routes in the order you add them to your RouteConfig file. Since the 'Default' route doesn't have any additional parameters on its URL definition, a call to "/1" won't match a route and you'll get a 404.
If you used a blank project, adding a RouteConfig file is a trivial matter. Just add a RouteConfig.cs file and define the class to contain the RegisterRoutes method I listed, then in your Global.asax file's Application_Start function, add a line for
RouteConfig.RegisterRoutes(RouteTable.Routes);
And you'll be good to go.
(EDIT)
I'm not certain that there still won't be conflicts, but you can combine Attribute routing with the standard routing paradigm by simply adding
routes.MapMvcAttributeRoutes();
to your RegisterRoutes function, immediately after the IgnoreRoute call, and the application will always defer to your Route attributes first, then check the defined routes.
However, since you've indicated you'd like to avoid using the standard routing approach altogether, you could simply define the attributes to take the following routes:
[Route("~/")]
[Route("st{id:int:min(2)}")]
public ActionResult Details (int id = "1")
{...}
To set a default value for the id parameter and avoid trying to handle the case in the attribute itself. Since you define a minimum value for the {id} parameter in your second Route attribute, you shouldn't have to worry about the case of "/st" trying to route to that action. It wouldn't match either defined route and so would 404.

Adding a parameter to the URL in ASP MVC

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.

Asp.net MVC routing ambiguous, two paths for same page

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.

Resources