Asp.net MVC custom routing - asp.net

I need to create a custom routing for this url:
/par1/par2/par3/par99/11
The url must redirect to
home/index/11
11 is the Id
I need only this parameter, the other parameter (par1/par2/...) are only for SEO purpose and could be any word.
par1, par2, etc.. are created dynamically , so the Url could be:
/par1/par2/11
or
/par1/par2/par3/111
or
/par1/3

you could just turn it around and go with
routes.MapRoute(
"Route",
"{id}/{*seostuff}",
new {controller = "Home", action="Index", seo = UrlParameter.Optional});
that will allow you to map urls such as http://www.somesite.com/11/whatever/goes-here/will-be-whatever-you/want

Maybe you'll start with this and adjust to your needs:
routes.MapRoute(
"Def0", // Route name
"{controller}/{action}/{seo1}/{seo2}/{seo3}/{id}"
);
routes.MapRoute(
"Def1", // Route name
"{controller}/{action}/{seo1}/{seo2}/{id}"
);
routes.MapRoute(
"Def2", // Route name
"{controller}/{action}/{seo1}/{id}"
);
routes.MapRoute(
"Def3", // Route name
"{controller}/{action}/{id}"
);

Since your id is at the end, you would need to make 99 routes to handle all the stuff in between in order for the id route to the controller (easily).
I would stick the id to the left of the "SEO stuff" if possible, so it can be thrown away easier, exactly like #Morder described. The {*seostuff} parameter catches forward slashes ('/'), whereas thee {seo1}, {seo2} parameters do not.
look at the way stackoverflow does urls; after the id everything is thrown away.

I know this has already been accepted but I've written a route class that allows greedy segment to be anywhere in the URL definition.
In this case URL definition would be
{*seo}/{id}
Read all details about the custom route class and use it if you like:
Custom Asp.net MVC route class with catch-all segment anywhere in the URL

Related

Why are these routes being matched?

The following code:
<li>#Html.ActionLink(metaTapp.Nav_About, "Mayla", "About")</li>
<li>#Html.ActionLink(metaTapp.Nav_Support, "Support", "About")</li>
<li>#Html.ActionLink(metaTapp.Nav_Exchange, "Index", "Exchange")</li>
<li>#Html.ActionLink("Post Rfq", "Create", "Rfq")</li>
is producing the following links:
<li>About</li>
<li>Support</li>
<li>Exchange</li>
<li>Post Rfq</li>
My Global Application Start looks like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UploadRouteConfig.RegisterRoutes(RouteTable.Routes);
LocalizationConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DatabaseFactory.SetDatabaseProviderFactory(new DatabaseProviderFactory());
}
}
UploadRouteConfig.RegisterRoutes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Upload", "Upload/Image", null).RouteHandler = new UploadMvcRouteHandler();
}
LocalizationConfig.RegisterRoutes
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
"Account", // Route name
"Account/{action}", // URL with parameters
new { controller = "Account", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"RfqCategory",
string.Format("{{{0}}}/Rfq/CategoryFilter/{{category}}", Constants.ROUTE_PARAMNAME_LANG),
new { controller = "Rfq", action = "CategoryFilter", category = Guid.Empty.ToString() }
);
routes.MapRoute(
Constants.ROUTE_NAME,
string.Format("{{{0}}}/{{controller}}/{{action}}/{{rfqid}}", Constants.ROUTE_PARAMNAME_LANG),
new { controller = "About", action = "Home", rfqid = "00000000-0000-0000-0000-000000000000" }
);
}
RouteConfig.RegisterRoutes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("TappDefault", "{controller}/{action}/{id}", new { controller = "About", action = "Home", id = UrlParameter.Optional }
);
I cant understand how upload is being matched to everything. If the route doesn't start with Upload/Image it should fall through to the localizationconfig routes?
Ok so the short answer to my problem is that I am rendering ActionLinks when I should be using RouteLinks. ActionLink will perform a match based on route table entries which seems like what I want but because I'm using a static Url:
"Upload/Image"
every url is matched. Why? Because routes are not filters. Routes work by matching supplied route values to the parameters of segments of the Url, but since:
"Upload/Image"
has no parameters i.e. {controller} then technically EVERYTHING is a match. RouteLink on tyhe pother hand allows me to specify which route to use when rendering the link:
#Html.RouteLink(
linkText: "route: Home",
routeName: "TappDefault",
routeValues: new {controller="About", action="Home"}
)
..
From Professional ASP.NET.MVC4 (Jon Galloway, Phil Haack, Brad Wilson, K. Scott Allen)
Page 232 Chapter 9 Routing:
Let’s suppose you add the following page route at the beginning of
your list of routes so that the URL /static/url is handled by the
page /aspx/SomePage.aspx:
routes.MapPageRoute("new", "static/url", "~/aspx/SomePage.aspx");
Note that you can’t put this route at the end of the list of routes
within the RegisterRoutes method because it would never match
incoming requests. Why wouldn’t it? Well, a request for /static/url
would be matched by the default route and never make it through
the list of routes to get to the new route. Therefore, you need to
add this route to the beginning of the list of routes before the
default route.
NOTE This problem isn’t specific to Routing with Web Forms. There are many cases where you might route to a non-ASP.NET MVC route
handler.
Moving this route to the beginning of the defined list of routes seems
like an innocent enough change, right? For incoming requests, this
route will match only requests that exactly match /static/url but will
not match any other requests. This is exactly what you want. But
what about generated URLs? If you go back and look at the result of
the two calls to Url.RouteLink, you’ll find that both URLs are broken:
/url?controller=section&action=Index&id=123
and
/static/url?controller=Home&action=Index&id=123
This goes into a subtle behavior of Routing, which is admittedly
somewhat of an edge case, but is something that people run into from
time to time.
Typically, when you generate a URL using Routing, the route values
you supply are used to “fill in” the URL parameters as discussed
earlier in this chapter.
When you have a route with the URL {controller}/{action}/{id}, you’re
expected to supply values for controller, action, and id when
generating a URL. In this case, because the new route doesn’t have
any URL parameters, it matches every URL generation attempt because
technically, “a route value is supplied for each URL parameter.” It
just so happens that there aren’t any URL parameters. That’s why all
the existing URLs are broken, because every attempt to generate a URL
now matches this new route.
This might seem like a big problem, but the fix is very simple. Use
names for all your routes and always use the route name when
generating URLs. Most of the time, letting Routing sort out which
route you want to use to generate a URL is really leaving it to
chance, which is not something that sits well with the
obsessive-compulsive control freak developer. When generating a
URL, you gener- ally know exactly which route you want to link to, so
you might as well specify it by name. If you have a need to use
non-named routes and are leaving the URL generation entirely up to
Routing, we recommend writing unit tests that verify the expected
behavior of the routes and URL generation within your application.
Specifying the name of the route not only avoids ambiguities, but it
may even eke out a bit of a per- formance improvement because the
Routing engine can go directly to the named route and attempt to use
it for URL generation.
In the previous example, where you generated two links, the following
change fixes the issue. We changed the code to use named parameters to
make it clear what the change was. #Html.RouteLink( linkText: "route:
Test", routeName: "test", routeValues: new {controller="section",
action="Index", id=123})

ASP.NET MVC Routing with a single optional parameter e.g. site.com/optionalparameter

I've been testing a few alternatives for a site that needs to support e.g.
site.com
site.com/Controller/Action/id
site.com/various.aspx
site.com/optionalparameter <-- these two go to the same controller
site.com/optionalparameter/ <-- these two go to the same controller
I actually need to verify if the optional parameter is acceptable, but I can direct it to a controller that will verify it. The other rules seem to work so far but I haven't been able to get the single optional parameter working yet.
The optional parameter in the url can be used with or without a slash "/" (at least without). I've found similar questions but they seem to have "optionalParam/xx/yy" so the rules have more parameters and they seem to work fine, but this is a bit of a special case converting a non-mvc site to use MVC routing.
An example of what I am trying to do, but isn't working.
routes.MapRoute(
"optionalParamRoute",
"{name}",
new { controller = "Home", action = "Index", name = "" }
);
Is this possible?
Try to move to top your optionalParamRoute parameter:
routes.MapRoute(
"optionalParamRoute",
"{name}",
new { controller = "Home", action = "Index", name = "" }
);
// other routes

How can be home controller define as root also when action have params? asp.mvc 4

By default if url is 'mydomain' it go to controller home; action = index.
But when index action has params the url have to be:
mydomain/home/index?name=John
want to get:
mydomain?name=John
What should be define for create such url?
Thanks,
Yosef
The correct url is the following:
http://mydomain.com/?name=John
Given default route setup this will invoke the Index action on Home controller and pass the name parameter.
As far as your request about the mydomain?name=John url is considered, well, this doesn't look quite a well formed url.
Are you sure you want mydomain/home/index?name=John and mydomain?name=John as your urls in your site?
If you corrected your routing engine, your routes could be, mydomain/home/index/john and mydomain/john, which to me would be more correct.
Is that what you're going for?
If so, assuming you have a Index action, accepting a string parameter of name in your home controller, you could modify your global.asax, and change the default route, and add a route below the standard default route like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", name= UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"NameOnly", // Route name
"{name}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
Be sure you put the name only route at the bottom, as a string based parameter will match everything, so you need to match the more explicit ones first.

where to use route-name of routing in aspnet mvc

i'm new to routing in aspnet mvc.. i have following code:
Action Controller
public ActionResult SchoolIndex()
{
return View(SchoolRepository.GetAllSchools());
}
here is the routing
routes.MapRoute(
"School", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "School", action = "SchoolIndex", id = "" } ); // Parameter defaults
when i enter "localhost/school" in addressbar, it is giving 404 error instead it should route to my "schoolIndex" action
i have given route-name as "School" where it is used ?
You can't specify a route name in a URI, ever.
Route names are for, e.g., Html.RouteLink(). RouteLink allows you to specify exactly the route you want, even if it's not the first matching route for the arguments you pass.
URIs are matched in order. The first matching route wins.
Read my post on routing for much more detail.

ASP.MVC routes without Details action

I'd like to have URLs that are even shorter than /{Controller}/{Action}/{Id}.
For example, I'd like {Controller}/{Id}, where {Id} is a string.
This would allow for simple paths, e.g. Users/Username, Pages/Pagename, News/Newsname. I like this better than requiring the /Details action in the URL (Users/Details/Username), which is less elegant for the end-user.
I can easily make this work by setting up custom routes for any controller that I want this level of simplicity for. However, this causes headaches when it comes to implementing other actions, such as {Controller}/{Action}, where {Action} = 'Create', since, in this case the string {Action} conflicts with the string {Id}.
My question: how can I have 'reserved' words, so that if the URL is /News/Create, it is treated as an action, but if the URL is anything else, e.g. /News/A-gorilla-ate-my-thesis, then it is treated as an Id.
I'm hoping I can define this when setting up my routes?
Update:
Using Ben Griswold's answer, I have updated the default ASP.NET MVC routes to be:
routes.MapRoute(
"CreateRoute", // route name
"{controller}/Create", // url with parameters
new { action = "Create" } // parameter defaults
);
routes.MapRoute(
"DetailsRoute", // route name
"{controller}/{id}", // url with parameters
new { action = "Details" } // parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
This works a charm and means, by default, the details pages will use the simplified URL, but I will still be able to target a specific action if I want to (update/delete/details).
Of course, you will need to disallow the reserved "Create" word as an Id, otherwise a user may try to create an article, for example, with the name "Create", which can never be accessed.
This is really nice. If anyone sees that there is something wrong with this approach, chime in, but I like it so far.
I think you're left with creating a route for each reserved word. For example,
routes.MapRoute("CreateRoute",
"{controller}/Create",
new { action = "Create" }
);
would handle /News/Create, /Users/Create, etc. As long as this route is listed before your other custom route, I think you're covered.
I imagine you will need addition routes for various CRUD operations which will follow a similar pattern.

Resources