I have setup a routing table in the global.asax file for images that have been moved to the database. When I use the url such that EmpImages/[numeric id] as a basic format, it works fine if I use the url that does that same ~/EmpImages/42, but we have hundreds of hardcoded links that are ~/EmpImages/42.png. When I try to use the EmpImages/[numeric id].png, the handler is never called.
I have looked at several samples that show the .ext, but they are using page routes instead of handlers. With the code below, can you tell me what I'm missing?
This part works:
RouteTable.Routes.Add(new Route("EmpImages/{id}/{size}", new EmployeeImageRouteHandler()));
RouteTable.Routes.Add(new Route("EmpImages/{id}", new EmployeeImageRouteHandler()));
When using the URL:
~/EmpImages/42
~/EmpImages/42/256
But when I try:
RouteTable.Routes.Add(new Route("EmpImages/{id}/{size}.png", new EmployeeImageRouteHandler()));
RouteTable.Routes.Add(new Route("EmpImages/{id}.png", new EmployeeImageRouteHandler()));
When using the URL:
~/EmpImages/42.png
~/EmpImages/42/256.png
It fails. The handler is never called.
What simple thing am I missing?
According to the documentation for Route, it seems that the way you are specifying the route is unsupported.
Quoting the docs:
The URL pattern consists of segments that come after the application name in an HTTP request... Each segment is delimited by the / character. When a segment is enclosed in braces ( { and } ), the segment is referred to a URL parameter. ASP.NET routing retrieves the value from the request and assigns it to the URL parameter... If the segment is not enclosed in braces, the value is treated as a literal value.
Apparently, it does not support segments with mixed URL parameters and literals.
You need to have your EmployeeImageRouteHandler internally deal with the ".png" extension of the size parameter with string processing.
EDIT: In addition to this point, it seems that there is a known problem in handling URLs with dots see this StackOverflow question . The solution proposed there is to include
<httpRuntime relaxedUrlToFileSystemMapping="true" />
in your web.config, but this works only for ASP 4.0 and IIS 7.0 and above. The details of this problem, as mentioned in the indicated question, are discussed on Haacked.
As far as I know, dmi_ above is right about route parses limitations. But you can draw a simple workaround from there:
Register your routes as folows:
RouteTable.Routes.Add(new Route("EmpImages/{id}/{size}/i.png", new EmployeeImageRouteHandler()));
RouteTable.Routes.Add(new Route("EmpImages/{id}/i.png", new EmployeeImageRouteHandler()));
And request them:
~/EmpImages/42/i.png
~/EmpImages/42/256/i.png
The issue is that the path you're attempting to catch with routing is a static resource. Routing is ignored if a file exists in the location of the route. This is by design and to both prevent conflicts between static url references and prevent the routing engine from being engaged for every single request.
Try putting a break point in your handler and then specifying an id that you know does not exists to see if this is the case.
Related
I am working on an existing ASP.NET webforms project - slowly updating to MVC. I am trying to conditionally override some of the existing webforms pages by routing to new MVC controllers. I can easily route an "example.aspx" URL to an MVC controller, but it doesn't work if there is an existing "example.aspx" file.
Example code:
routes.MapRoute
(
name: "example",
url: "example.aspx",
defaults: new
{
controller = "Example",
action = "Index"
}
constraints: new { useMvc= "1" }
);
The code above works fine, and routes to the controller as expected, unless there is an existing "example.aspx" file in my solution - in which case it routes to that instead. But that's exactly what I'm trying to override.
Are existing webform routes given preferential treatment? Is there some way to circumvent this?
I've found mechanisms to do the reverse by using MapPageRoute(), but as far as I can see, that doesn't help me.
You can configure your application to ignore specific routes that your are handling through MVC. You could add the following line before registering a new route:
routes.IgnoreRoute("{*path}/example.aspx");
Hope this helps.
I haven't solved the problem as stated, but I've found a work-around that will accomplish the same result.
1) I renamed the "example.aspx" file to something else "foo.aspx"
2) Added the MapRoute() similar to my original question (with the constraint)
3) Used MapPageRoute() to route all other "example.aspx" calls to "foo.aspx"
I also ended up having to use the QueryStringConstraint logic as described by
another stackoverflow answer: but that's a separate issue.
I'll leave this question open for a few more days to see if there is a "real" solution before marking my own answer.
I would like my ASP.NET MVC4 application to only serve the base HTML markup for a specific page, and after that I'm processing everything else on client-side with knockout.js/history.js/AJAX, including the initial page load.
So when someone refers to URL http://example.com/products/list/food/fruits, the MVC router should simply ignore everything what is behind "products/list" and route the request to ProductsController and List action. Then on client-side I will handle the rest and load the requested data accordingly.
I was playing with the route definitions, I tried to completely skip the "products/list" route, I also tried to add a "products/list/*" route, but didn't have success yet.
You can use an asterisk as part of the last variable in a route. For example, when configuring your routes:
routes.MapRoute(
"ProductRoute",
"products/list/{*otherArgs}",
new { controller = "Products", action = "List" });
You can learn more in MSDN's Documentation on routing under the section "Handling a Variable Number of Segments in a URL Pattern"
You will need to create your own route.
Something like this should do the trick:
routes.MapRoute("Products", "Products/{List}",
new {controller = "Products", action = "List"}
);
Note: I´m not sure if the other parameters are required in the route.
I have seen this post: MVC Handler for an unknown number of optional parameters but it's for MVC and doesn't seem to work for me as I get an error:
A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter.
I want to be able to have an indeterminate amount of params in a Url, I have the following route:
RouteCollection.MapPageRoute("ManyParam", "{*params}.html", "~/Default.aspx");
This also seems to trigger the error message above.
How can I set up a route to have an unknown number of parameters in web forms (not MVC).
I am trying to achieve the following urls:
www.example.com/some-thing.html
www.example.com/some-thing/else.html
www.example.com/and/some-thing/else.html
www.example.com/1/2/3/4/5/6.html
EDIT
It seems to work when I use the following:
RouteCollection.MapPageRoute("ManyParam", "{*params}", "~/Default.aspx");
The problem is with this is that it doesn't allow the .html at the end.
Untested route below - the wildcard one have to be absolutely last portion of Url. So to force ".html" at the end you need to use constraint (5th argument).
routes.MapPageRoute(
"ManyParam",
"{*path}",
"~/Default.aspx",
false,
new RouteValueDictionary(),
new RouteValueDictionary { { "path", #".*\.html" } }
);
i want to route Default.aspx to another URL when page starts.
my global.asax is like this :
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute(
"Default", // Route name
"My Site", // URL with parameters
"~/Default.aspx" // Parameter defaults
);
}
should i write a handler for my purpose?
(i found some samples for .net 3.5 and MVC but what about .net 4 web forms)
if yes how can i write it?
EDIT:
what this line exactly do?
routes.Add("Default", new Route(string.Empty, new RouteHandler("~/Default.aspx")));
i am using web forms -> Not MVC
thanks in advace
Here's a specific example of how to deal with routing on asp.net 4.0 web forms (it's just under the mvc part).
http://weblogs.asp.net/scottgu/archive/2009/10/13/url-routing-with-asp-net-4-web-forms-vs-2010-and-net-4-0-series.aspx
The way you are approaching it is fine. You do have an error in the second parameter of your route. Well perhaps not an error, I dislike spaces in urls as they are actually the encoded spaces. Check out the guide.
Just noticed your edit.
Adding the route essentially creates a mapping between a url or url pattern (which you have as string.Empty which is a problem) and a handler which serves the request(You specify RouteHandler which I don't believe actually exists?). .net Provides a PageRouteHandler which allows you to specify which page responds to your request and deal with a couple other details like security defined on the physical structure of your site. Internally, MapPageRoute is simply calling routes.Add but using the PageRouteHandler.
I have an existing site that I'd like to convert to use routing, and after reading Scott Guthrie's post here, I built a working sample that works for most circumstances. However, since not all of the pages on the existing site match a particular pattern, I'll need to check against a database to determine which route (destination .aspx page) to use.
For example, most pages are like this:
http://www.mysite.com/people/person.html
This is fine - I can easily route these to the view_person.aspx page because of the 'people' directory.
But some pages are like this:
http://www.mysite.com/category_page.html
http://www.mysite.com/product_page.html
This necessitates checking the database to see whether to route to the view_category.aspx page or the view_product.aspx page. And this is where I'm stuck. Do I create an IRouteHandler that checks the database and returns the route? Or is there a better way? The only code I've found that kind of fits is the answer to this question.
Thanks in advance.
If you don't mind doing so, the cleanest solution is to:
http://www.mysite.com/pages/category_page.html
In ASP.NET MVC, this situation would be handled a little differently, by specifying a default controller and action method on the root route.
Your route handler doesn't check the database. It sends all the requests to a handler .aspx script. It's that script that checks the database.
My register route looks like...
private static void RegisterRoutes()
{
Route currRoute = new Route("{resource}.axd/{*pathInfo}",
new StopRoutingHandler());
RouteTable.Routes.Add( "IgnoreHandlers", currRoute);
currRoute = new Route("{urlname}",
new EPCRouteHandler("~/Default.aspx"));
currRoute.Defaults = new RouteValueDictionary {{"urlname", "index.html"}};
RouteTable.Routes.Add( "Default", currRoute);
}
The custom handler, which shouldn't be needed in ASP.Net 4.0, simply passes the urlname parameter to the responding script as a URL variable.
Now how often the responding script checks the database depends on how often the data in the database is changed. You can easily cache paths and invalidate the cache when the data is suppose to have changed for instance.
For anyone stuck in the same situation, I ended up adapting the code from this answer to check against a database and return the proper ASPX page.