Url Routing for unknown number of params - c#

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" } }
);

Related

How to use regular expression to match part of url in route part? WebAPI .NET core 2.2

I am now trying to write a WebApi app. In route part (controller), I want to use regular expression to match part of url. However, it seems that "/" cannot be recognized well.
For example, the api url is "api/books/science/list". I want to get "api/books/science" and "list". I have tried the following regular expression [HttpGet("{url=.*}/list")]. But it seems the regular expression doesn't work. ".*" can not match "\".
The api is designed like "api/*{path}/list". For *{path}, it may have multi structures such as books/science or books/art/Asia'. I want to use regular expression to match them and then, they can be used for the following operations.
Actually, I have tried another method to get the url [HttpGet("{**url}")]. But I suppose it is not a very good solution because I need to parse the url then.
Regex is supported through the :regex() parameter. See Routing in ASP.NET Core documentation on Regex for information, and Routing Middleware for example.
Try: [HttpGet("{url:regex(.*)}/list")]
As you pointed out this doesn't work because it works on the tokenized value of route url.
One alternative is to use catch-all in routing (in Startup.cs):
routes.MapRoute(
name: "therest",
template: "/{**url}",
defaults: new { controller = "Home", action="Index"} // Send to /home/index
);
Or if you know there will be limited number of path elements, you can simply include them all:
[HttpGet("/{url1}")]
[HttpGet("/{url1}/{url2}")]
[HttpGet("/{url1}/{url2}/{url3}")]
[HttpGet("/{url1}/{url2}/{url3}/{url4}")]
public IActionResult Test(string url1 = null, string url2 = null, string url3 = null, string url4 = null)
{
var url = string.Join("/", url1, url2, url3, url4);
//... return View();
}
The alternative I believe is to write some additional routing code in the middlelware.

Azure function optional "middle" route parameter

I want to make the "middle" route parameter optional in Azure functions. Ex:
public static HttpResponseMessage MyFunction([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "SomeRoute/{MyOptionalRoute=int?}/AnotherRoute")]HttpRequestMessage req, TraceWriter log,
int MyOptionalRoute = 0)
{
//some magic
}
This method works if i give MyOptionalValue a value. For example : /SomeRoute/123/AnotherRoute
But returns a 404 if i dont: Ex: /SomeRoute/AnotherRoute
Do anyone know if there is a way to get around this so that i dont have to create two seperate functions? I have been looking around and all i see is people using the optional route parameter as the last parameter in the sequence. Maybe i just dont know what keywords to google or is it just not possible?
Appreciate all help i can get.
Thanks.
As you have found, Azure function doesn't support optional “middle” route parameter yet. Only consecutive optional parameter like SomeRoute/{MyOptionalRoute:int?}/{AnotherRoute:int?} works.
Back to the point, find a workaround with proxy for function, see whether it meets your requirement.
Add a proxies.json to your function project, change file property copy to output directory to copy if newer.
See content below, I use 0 as the reserved number as the alternative of null value. Proxy directs http://localhost/api/SomeRoute/AnotherRoute to the real url http://localhost/api/SomeRoute/0/AnotherRoute, which matches the pattern of SomeRoute/{MyOptionalRoute:int}/AnotherRoute.
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {
"proxy1": {
"matchCondition": {
"methods": [ "GET" ],
"route": "/api/SomeRoute/AnotherRoute"
},
"backendUri": "http://localhost/api/SomeRoute/0/AnotherRoute"
}
}
}

How to ignore all characters after "controller/action" in an ASP.NET MVC route?

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.

How to route an url with an url in it in MVC

Basically I would like to take an url like:
http://example.com/community/www.foo.com/bar
...and give it to my http://example.com/community/ view with www.foo.com/bar in some variable that razor can access in the view.
How could this be done?
Note: I tried this:
routes.MapRoute(
"Community",
"{controller}/{url}",
new { controller = "Community", action = "Index", url = "" }
);
which worked with http://example.com/community/www.foo.com but not http://example.com/community/www.foo.com/bar (IIS tried to resolve the latter and gave a 404).
From MSDN:
Sometimes you have to handle URL requests that contain a variable
number of URL segments. When you define a route, you can specify that
if a URL has more segments than there are in the pattern, the extra
segments are considered to be part of the last segment. To handle
additional segments in this manner you mark the last parameter with an
asterisk (*). This is referred to as a catch-all parameter. A route
with a catch-all parameter will also match URLs that do not contain
any values for the last parameter. The following example shows a route
pattern that matches an unknown number of segments.
query/{queryname}/{*queryvalues}
In your case it will be:
routes.MapRoute(
"Community",
"{controller}/{*url}",
new { controller = "Community", action = "Index", url = "" }
);
Alternative and more robust approach is using some kind of encoding for the URL part - for example Base64URI encoding from RFC4648

ASP.NET MVC route handling for misspelled URLs?

How can we create a route that will detect that the URL matches a route but that the parameter to that route is wrong?
I've had several cases recently where a user has mistyped a URL and it has been hard to debug because the route table doesn't handle these misspellings very gracefully:
This route handles the URL /Widgets/guid
routes.MapRestfulRoute(
"WidgetsItem",
"Widgets/{idString}",
new { controller = "Widgets", action = "Item" },
new { idString =
#"^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}$"}
);
routes.MapRoute("WidgetsList", "Widgets", new { controller = "Widgets", action = "List" });
routes.MapRestfulRoute("CatchAll","{*url}", new {controller = "Error", action = "Http404"});
And the user entered the URL /Widgets/25246810-4b60-4db8-8567-8db8826 which looks correct but is not (there's only 28 characters in that guid provided).
Because the URL didn't match the route, the response was 404. But this is deceptive and caused a debugging problem: it looks like the Widgets/Item action is returning 404. And we spent hours trying to figure out what was wrong with that action, when in fact the action wasn't even called. It wasn't until I installed RouteDebugger that I noticed the guid was malformed.
How can we create another error route that will detect that the URL does actually match a route but that the parameter to that route is wrong?
EDIT: I can "fix" it by adding a new route that matches /Widgets/anything, and placing that route after the normal route:
routes.MapRestfulRoute(
"WidgetsItemError",
"Widgets/{idString}",
new { controller = "Widgets", action = "Item" },
new { idString = #"^.+$" } // match if it has any param at all
);
But this seems to be very inefficient - I will have to add a similar error route for every single route eg /Foo, /Bar /FooBar etc (and I've got quite a lot of routes). Isn't there a more generic way to do this?
When I dealt with guid's in my routes, I would accept a string, try to parse the string value to a guid, if it didn't parse, i'd return a different view with a message indicating that the id was invalid and to try again
The only thing you should have to change here would be to remove the route constraint and change your Action to accept a string instead of a guid (unless your action is already accepting a string)
The easiest solution is to remove the route constraint, then check for a null parameter in your controller and do whatever you want from that point.

Categories