MVC 3 Custom routing from sql - asp.net-mvc

I'm working on a CMS/Webshop engine with a MVC 3 front-end. I want to be able to define url "aliases" for dynamic content/products runtime, and I want to be able to route this URLs to MVC controller actions.
For example I want to be able to define
~/Products/Motherboards/{manufacturer}/{uniqueName}
~/HugeSavings/{uniqueName}
~/Products/{uniqueName} etc.
to map to the same Display(string uniqueName) controller action in ProductsController. These url patterns are dynamic, even the rules for their order or composition is NOT DEFINED at design time, the pattern's rule or pattern's content can change in runtime without restarting the application, they are stored in SQL, but needs to be cached. Each pattern has a target which may be a typical MVC url like
Products/Display/{uniqueName}
or a direct link like
`http://somestuff.com/stuff.aspx?name={uniqueName}.
Every solution I've found used
RegisteredRoutes.Clear();
RebuildRoutes();
which is horrible, because of this for adding one new pattern for one product (or product category) I have to query the database for thousands of products and their corresponding patterns.
So, can I change routes without clearing or restarting the app? Can I "inject" some logic to routing WITHOUT having to recode the whole "look up the controller and action and parse the parameters" thing.

Yes, you can add routes later. Just don't RegisteredRoutes.Clear(); them first.

If you're still intereseted, I just answered a very similar question regarding fully dynamic routing in MVC.
Multilingual URLs with ASP.NET MVC

Related

ASP.NET MVC Specify Category/Path outside of URL Routing

I have a problem to make a decision for putting Category/Path on URL Routing. Assume I have some products in my sample Web Application those attached to some categories. For example:
Book1 Attached to -> Category1 | Category2
Book2 Attached to -> Category1 | Category2 | Category3
Book3 Attached to -> Category2 | Category3
And defined routing map for products is:
url: "{controller}/{action}/{languageCode}/{category}/{product}"
defaults: new { controller = "Home", action = "ViewItem" }
So possible routing for Book1 are:
[Domain Name]/Home/ViewItem/en-US/Category1/Book1
[Domain Name]/Home/ViewItem/en-US/Category2/Book1
And possible routing for Book2 are:
[Domain Name]/Home/ViewItem/en-US/Category1/Book2
[Domain Name]/Home/ViewItem/en-US/Category2/Book2
[Domain Name]/Home/ViewItem/en-US/Category3/Book2
I want to save and know current category but have single unique URL for each product(For search engine tracking and sharing URLs purpose). I think about using Session Variable or ViewBag even Cookie, But each of them has own limitations and cons. For example using cookies may cause some troubles: if set expiration time too small, it may lost current path when user pausing on some pages and if set it too long, may lead user to old browsing path even user requested for home page in new opening browser because of existing cookie (Except that, I'v some experiences with cookies and I believe that is not working precisely all times), About Session and ViewBag I don't know if using them is the best idea, So can anyone share tested solution or good idea? I will appreciate that.
You should have the page mywebsite.com/product1 (the canonical version of the URL). Including all the versions of the URL won't help. Likely, it will just confuse Google and may lead to Google ignoring certain URLs
Even if you put in the canonical version and have the rel canonical tag on your pages, Google may still choose to treat another version of the URL as canonical.
Ideally, then, I'd solve the real problem here and just have one version of the product URL on your site (have the versions with the category in the URL redirect to the version of the URL with no category in the URL). That way you don't even have to worry about all the issues duplicate content may cause.
I suspect this isn’t a routing problem, rather an architectural issue. I think that the “language code” and “category” should be an attribute of the Book object, rather than being a part of the route.
You would then have URLs like:
{domain}/{controller}/book/id
And for “category” specific or “language code” specific views, you could have URLs like:
{domain}/{controller}/search?languageCode=enUS&category=1
This would still be perfectly RESTful and in my opinion, much simpler as well.

Route with generic parameter

doubt came here with ASP.NET MVC.
Has as make a system with "areas" that generic?
Example: meusite.com / nome_area {} / {parameter}
where the parameter would say that would appear on the page.
In a news site for example, if the parameter in the URL would: meusite.com / {area} / city_name, content that would appear in the area would be linked that city.
If you recall when it comes to Routing, you know that ordering of route registration is very important. So, generic routes may be difficult to order and hence not possible.
You can find more information on this blog.

Maintain parameter info in the request path for all pages instead of the subdomain

I seek some guidedence here ... ( I'm not sure if this is the best title )
At the moment I prepend a "server name" to the url like this:
server10.example.com
This works fine, except that I need to handle all the subdomains on the IIS and I'm not sure google are happy about jumping around from sub to sub to sub, when it seems the links to the other servers.
I'm kind a hoping for a nice way to archive this wioth asp.net mvc.
Most pages are related to a "server" ... there are however a few info pages, contact, home that dont really need a valid "server" name ... but could just be "na" for not available, but the name need to be maintained, if there is already a selected server, when a user are keeps browsing the site. This needs to be as transparent as possible when I need to create the links to the diffenrent pages.
I could extend the Html Action() extensien to automatically add the selected "server" from the previusly request to the page.
In the format:
/{serverParameter}/{controller}/{action}/{parameterInfo}
And if no server is selected, just add "na" as the {server} placeholder.
I'm not sure if more information is needed, but please let me know if ...
I tired of extracting the selected server from the domain part and the other way also seems better, I just can't think of a good way to structure this ...
Updated
90% of all the pages are about a server that the user select at some point. Could be server10, server9, server20 ... just a name. I want to maintain that information across all pages, after the users has selected it or else I just want it to be f.ex: "empty".
I mostly looking for an easy way of doing this or an alternative ... atm I'm prepending the serverParamter to the url so it ends up being: "serverParameter.example.com".
I want to end up with something like
http://example.com/{server}/{controller}/{action}
instread of
http://{server}.example.com/{controller}/{action}
If I understand your question correctly, you just wish to group different collections of content together above the controller/action level. If that's the case, have you considered using ASP.NET MVC areas?
Just right-click on your project, and choose Add -> Area.... Give it a name (what you're calling "server"), and then you can add content, your own controllers, actions, etc. Under this area. You will automatically be able to access it via /AreaName/Controller/Action/etc.
I went with the already impemented routing in ASP.NET MVC.
{server}/{controller}/{action}
When creating the links it takes the set value for {server} and places the value when generating URL's, so I only need to supply controller and action in the #Html.Action helper method ... this could not have been more easy.
I'm not sure why I did not think about this. One just gotta love routing.

How do I make Duplicate action RESTful

I have a very simple Rails application that performs regular CRUD operations on an object (Path), this all fits nicely in the REST philosophy of Rails. Now however, I need to add a "Duplicate" feature (i.e. create new path from existing path). I have added it as an (RESTfull) action in my path_controller, so far so good (maybe not completely in line with the REST philosophy but I am not a purist).
Now I want to extend the functionality so that the users can choose to either create a completely new path from an existing one or copy the existing path to another, already existing path (duplicating its children). This means I am going to need a few extra Views:
one that allows them to pick Option 1 (Create New Object) or Option 2 (Duplicate to existing Object).
If they choose Option 2, I need another View that lets them then pick the path they want to copy to.
Each of these views needs a corresponding action, and it is here that I am struggling as to where this all fits in REST.
This is a fairly simple example but as my UIs get more complex, I always run into this issue: How do I make my actions I need for my UI fit in REST controllers?
Just add a new collection route to your resource:
resources :paths do
collection do
get :duplicate
end
end
and add a duplicate method to your paths controller and views for it...
now you can access and address specifi routes for your users choice.

Pitfalls of deviating from the {controller}/{action}/{id} REST URL format for ASP.NET MVC?

I will be launching a new site soon. One section of the site contains products.
I am currently trying to decide between different URLS for the ASP.NET routing :
**Products: **
/products/1001
/products/sku/1001
/products/product/1001
/products/view/1001
**Categories: **
/products/category/cats
/products/category/clothing
/products/cats - this is pretty nasty
/products/clothing
I am primarily trying to decide which of the following I should adopt.
I am currently doing the first.
routes.MapRoute(
"product-route-short",
"products/{sku}",
new { controller = "Products", action = "ViewProduct", sku = "1001"}
);
or
routes.MapRoute(
"product-route-short",
"products/sku/{sku}",
new { controller = "Products", action = "ViewProduct", sku = "1001"}
);
or one of the following
* call the action 'sku' , 'details' , 'item'
* use an [ActionName] attribute and leave the action method name as 'ViewProduct'
I really like the simplicity of /products/1001 so the user can see it and change it - but there is quickly a danger of it conflicting with other actions if I'm not careful. I also have to be sure to use 'product-route-short' when creating my URLS which is a very minor pain.
What does anyone think? What have you found a best practice to be? This example is pretty simple, but I want to be consistent across the site of course and don't want to have to retrofit everything once Google has already indexed everything for me.
If there are any especially good podcasts or articles on the subject (general or specific to ASP.NET) I'd appreciate links to them. I found a good podcast where one thing they specifically said was that 'this podcast is NOT about how to create good REST links'
I would gear my URLs towards these goals...
1) Usability. It's really nice if you can tell what kind of page you'll get if you look at the URL. If it's short enough to type and/or guess, all the better.
2) Search Engines. You really want to get your keywords into those URLs. I know you want to use the ID to look up the product, but human beings and search engines want to see the product name there. Also, the closer a key word is to the start of the URL, the more importance is placed on it.
This is really just a skimming. If you want the best URLs you'll need to ensure the categories and product names are unique so you can look them up rather than using IDs in the address.
My suggested convention would be...
/products/
/products/clothing/
/products/clothing/blue-suede-shoes/
Note that SO itself lists this question on stackoverflow.com/questions/625213 (the / afterwards is ignored). So you at least have precedent :).
I think the shorter URLs you are making are fine. The beauty of the asp.net mvc routing engine is that, assuming you have made your links correctly in the views, you can make changes to the routes as you develop. So feel free to play around as you go.
Another thing to keep in mind is the constraints argument in the MapRoute method. You can always try something like this:
routes.MapRoute(
"product-route-short",
"products/{sku}",
new { controller = "Products", action = "ViewProduct", sku = "1001" } ,
new { sku = #"[0-9]" }
);
routes.MapRoute(
"product-route-other",
"products/{action}/id",
new { controller = "Products", action = "ViewProduct" }
);
That filter will make it so only skus between 0-9 will work. Obviously you would want to use a regex to fit your particular scenario, but that would help you avoid conflicts with actions. In this situation, if the value for sku was not between 0-9 then the routing engine would go to the next route and try to match that. It will do this until it finds a match.
With the combination of routes and constraints you should be able to have very clean url that make sense to the user.

Resources