How to approach making a controller with (unlimited) db look-up routes - asp.net

I'm digging into ASP.NET MVC from classic asp, and have completed some tutorials. I understand the concept now, but I have a main question about the controller. How are you able to control the url structure if you are getting your url's (with params) from a sql database?
Example: /custom-url-1 or /custom-url-23423411
(Returns params accordingly to feed the code)
I'm guessing it would have to do with ActionResult Index() , but not sure where to go after that. Any idea's where to look or is this even possible? Does MVC even allow this?

One Way you can approach this is to have everything go to one action in one controller and resolve the content in the view.
This is useful only if you have one type of view.
Second way is to have route constraint or a custom route constraint for each type of content you have
say : Galleries, Blog, Pages
and in each constraint check if the given url is of this type ( by db call), if the constraint returns true, it will point the request to the given controller and action.
The third way is to have a custom route handler that does the checking and routing (mind you this is probably the hardest task but works best if you have complex system, if your is simple try using method 1 or 2
P.S. if you want your urls separataed by "-" instead of "/" you can do just this
routes.MapRoute(
"Default", // Route name
"{controller}-{action}-{id}",// URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);

Related

Capturing an incoming webforms request in an MVC route

I'm converting a legacy webforms app to MVC, working through it a page at a time. To make the project easier to work with I've moved all the webforms pages, which were previously in the route of the project into a /webforms subdirectory. So I need to capture any incoming requests for /page.aspx?param=123 and redirect them to /webforms/page.aspx?param=123. I thought an easy way to do this would be to setup a route handler that passed any such requests to a controller that does that job. I set up a route like so:
routes.MapRoute("WebformsRedirect", "{*page}",
new { controller = "Webforms", action = "ForwardToPage" },
new { page = #"\S+.aspx\S*" }
);
This kind of works but it doesn't capture the query string, only the page part. I can get the query string for the Request object in the controller so it's not a huge deal but it would be nice to be able to do it through the route only. My routing unit tests (which I copied from Steve Sanderson's MVC book) actually pass correctly when I test them with querystrings so I'm confused why it isn't working. Is my regular expression wrong? They aren't my strong point.
QueryStrings are not part of the routing
if you requested for example "Home/Index?foo=bar" and you have a route that match "Foo/Bar" to Controller Foo , Action Bar without any more routing info (don't know anything about foo) you still can write
class HomeController: Controller {
ActionResult Index(string foo) {
}
}
now foo variable will equal bar , why ?
because its the model binder that gets the value of the parameters passed.
the model binder check 4 repositories by default QueryString , Routing Place Holders ,FormsCollections and Files
so what i am trying to say , the route and QueryStrings are two different things , it doesn't need to capture it

What is Ambient Route Values in ASP.NET MVC and how it works?

I am new to ASP.NET MVC. I read Professional ASP.NET MVC 3 and it has two pages talk about Ambient Route Values but I don't understand how it works. I search "asp.net mvc ambient route values" on google and still not find any articles or websites that explain what is it or how it works.
I want to know what is "Ambient Route Values" in ASP.NET MVC? How it works?
Ambient route values are related to all those values that are not needed for the current route outbound processing.
Let's explain through an example
Take for instance this route definition:
routes.MapRoute(
"Complex",
"{securityArea}/{permission}/{action}/{id}",
new { controller = "Administration", action = "List", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The scenario of ambient route values in this case would be:
User does some administration, so he's currently on URL served by the first route definition:
/users/change/apply/45
He edits some form on this URL and posts data back.
When he hits the server (executes some controller action), all of those route values get populated and are part of the context's route values now.
Controller does what it has to do and in the end we want it to redirect to non-admin part of the application, so hitting the second Default route.
Now if we take a look of the URL generation in #4. What happens?
route values that are defined during request are:
controller = "Administration"
action = "Apply"
securityArea = "Users"
permission = "Change"
id = 45
Only the first two are needed to generate the URL of the second Default route
What happens with the rest ambient route values?
They get added to the URL as well:
/Home/Index/?securityArea=Users&permission=Change
And we don't want that.
That's why they're called ambient because they are just *hanging in there orphaned in the request. This is my explanation of ambient route values. Hopefully explained in an understandable way.
I've also written about removing these ambient values in one of my blog posts where I've provided a custom route class that does this removal.
As referred on page 232
Ambient route values in the book that you linked also refer to outbound route processing but it talks about ambient values as those that we don't need to supply for outbound route processing because they will be taken from current values (namely controller and action may as well be ambient values).
Book though doesn't talk about the problem with ambient route values that I outlined in my upper answer. All defined route values can be ambient and they may cause problems when we don't realise how routing works.
The url generated does not need to contain the controller or action params of the current request. The page param indicated in the example is matched as one of the params in the RouteData, and the controller and action, since they weren't supplied, remain as they are on the current request.

Asp.NET MVC Route Performance

I have an application with a couple thousand routes.
This is because for each product we use a custom URL, as opposed to the textbook /product/id.
With this many urls, the performance is unacceptable in the router.
I am trying to find ways to improve it, but I am drawing a blank.
I have about 20 regex routes and about 3 thousand unique url routes.
Any Ideas?
Sorry for being so open ended, but I am not sure where to start.
If your urls are all on the format yoursite.com/{url}, you can still store all the three thousand urls in the database, and create a custom controller factory which uses the {url} parameter to look the correct information up in the database and assign correct controller, action and any parameters you're using.
There are lots of posts on google on how to implement the controller factory.
I imagine you'll also want some parsing of the existing routes to put them all in the database - this can probably be done by iterating over the RouteTable after you instantiate your application (i.e. after RegisterRoutes() is called).
I would get rid of the 3 thousand unique url routes and replace them with a generic route that is the last catch-all route. Something like:
routes.MapRoute("productRoute", "{category}/{manufacturer}/{productTitle}", new { controller = "Products", action = "Index", category = UrlParameter.Optional, manufacturer = UrlParameter.Optional, productTitle = UrlParameter.Optional });
You could also then add a custom IRouteConstraint to validate that the category exists (but just make sure it doesn't hit your database every time or performance will degrade).

ASP MVC Routing

now this is probably an stupid question but i'm new to mvc and can't seem to get it working.
Here is what i would like to be able to do with the urls/routes:
1) www.domain.com/name/home/index
2) www.domain.com/home/index
where both the home controllers are seperate controllers and the name part will very but all must go to the same controller and the name should be an param for all the actions in there.
Is this at all possible? Thanks for your help.
This might not be the answer you're looking for, but I think that it would be more usual to see
www.domain.com/home/index
www.domain.com/home/index/name
My initial thinking was that an overloaded Index action method would make sense, but Daniel pointed out that this not allowed (at least not in the manner I suggested).
Updated answer...
Your Index action method could take a string name argument, and your routes would need to contain something like
routes.MapRoute(
"Default",
"{controller}/{action}/{name}",
new { controller = "Home", action = "Index", name = "" }
In your action method a quick null check will tell you whether a name was included in the URL or not.

ASP.NET MVC retrieving route to controller, action and parameters

In ASP.NET MVC how can I generate a URL to a specific controller and action along with other parameters. The RedirectToAction allows me to redirect, but I would like to retrieve this URL instead from within my controller.
I tried using:
Url.Action("Page", "Administrator", New With {.page = _currentPage})
But that returned a link like /Administrator/Page?page=2 whereas I was hoping to retrieve something like /Administrator/Page/2
I've searched countless forums and I'm sure there is something around for this, but I cannot find it for the life of me.
Thanks!
What do your routes look like? The standard route expects an id as the third parameter. If you haven't changed your routes, try using:
Url.Action( "Page", "Administrator", New With { id = _currentPage } )

Resources