Reputation: 15701
The following route will match any folder structure below BasePath:
http://BasePath/{*SomeFolders}/
How do I create another route which will match any zip file below the same BasePath structure?
I tried this...
http://BasePath/{*SomeFolders}/{ZipFile}
... but it errors with
A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter. Parameter name: routeUrl
How should I approach this?
*Update*
The original requirements are in fact flawed. {ZipFile} will match the final section regardless of what it contains. (File or Folder)
In reality I believe the route pattern I'm looking to match should be:
http://BasePath/{*SomeFolders}/{ZipFile}.zip
Upvotes: 6
Views: 3557
Reputation: 15701
It seems that constraints are the answer here.
routes.MapRoute( _
"ViewFile", "BasePath/{*RestOfPath}", _
New With {.controller = "File", .action = "DownloadFile"}, _
New With {.RestOfPath = ".*\.zip"}
)
routes.MapRoute( _
"ViewFolder", "BasePath/{*RestOfPath}", _
New With {.controller = "Folder", .action = "ViewFolder"} _
)
or for those of you who prefer C#...
routes.MapRoute(
"ViewFile", "BasePath/{*RestOfPath}",
new {controller = "File", action = "DownloadFile"},
new {RestOfPath = @".*\.zip"}
);
routes.MapRoute(
"ViewFolder", "BasePath/{*RestOfPath}",
new {controller = "Folder", action = "ViewFolder"}
);
(Erm I think that's right)
The same route is registered twice, with the first variation being given the additional constraint that the RestOfPath parameter should end with ".zip"
I am given to understand that Custom Constraints are also possible using derivatives of IRouteConstraint.
Upvotes: 6
Reputation: 105029
I've written such Route
class that allows you to do exactly what you describe. It allows you to put catch-all segment as the first one in the route definition (or anywhere else actually). It will allow you to define your route as:
"BasePath/{*SomeFolders}/{ZipFile}"
The whole thing is described into great detail on my blog post where you will find the code to this Route
class.
Based on added info I would still rather use the first route definition that doesn't exclude file extension out of the route segment parameter but rather add constraint for the last segment to be
"[a-zA-Z0-9_]+\.zip"
So routing should still be defined as stated above in my answer, but contraint for the ZipFile
should be defined as previously written. This would make my special route work out of the box as it is now.
To also make it work for other route delimiters (like dot in your example) code should be changed considerably, but if you know routing very well how it works, you can change it to work that way.
But I'd rather suggest you keep it simple and add a constraint.
Upvotes: 4
Reputation: 47375
As the error says, your catchall has to be the last param in your route.
To get the ZipFile part out, you will have to parse it from the SomeFolders catchall:
public ActionResult MyAction(string SomeFolders)
{
// parse the ZipFile out from the SomeFolders argument
}
So if you have /folder1/folder2/folder3/file.zip, you can do this:
var zipFile = SomeFolders.SubString(SomeFolders.LastIndexOf("/") + 1);
Upvotes: 1