Aspnet greedy route parameter - asp.net-mvc

I have mapped route:
routes.MapRoute("test", "/{p1:int}-{p2}", new { controller = "test", action = "int" });
Such route should match int-string, like /1-stuff, and it works for such cases, however it does not work for /1-stuff-stuff. I guess this is because route is matched and then params are rejected because of int constraint.
If I remove constraints p1 equals 1-stuff, and p2 equals stuff. Is there way to apply constraints in correct way or to mark p2 as "greedy" (but not catch-all), so p1 equals 1 and p2 equals stuff-stuff?
This is very important for making human-firendly urls, where ids are at front and everything is kebab case without additional characters.
Catch-all does not work for me I need p2 to be bound to action parameter. Regex does not help.

why not try something like ...
Routes.MapRoute(
name: "test",
url: "/{p1}",
defaults: new { controller = "test", action = "int" },
constraints: new { p1 = "^\d+-[\w-]*\.*$" }
);
... and then parse p1 inside your action
The regular expression might need a bit of adjusting depending on your requirement, but in this scenario p1 would be '1-stuff-stuff' then you can split("-") p1 to get your values

Related

Query to find all shortest path with additional condition returns no records

I have to find all shortest paths between A and B with additional property.
This query returns me only one route (and this is true, there is only one route which has 3 parts):
MATCH (darjeeling { name: 'Darjeeling' }),(sandakphu { name: 'Sandakphu' }),
paths = allShortestPaths((darjeeling)-[*]-(sandakphu))
RETURN paths
Results:
{"start":{"identity":1,"labels":["town"],"properties":{"name":"Darjeeling"}},"end":{"identity":3,"labels":["peak"],"properties":{"altitude":"12400 ft","name":"Sandakphu"}},"segments":[{"start":{"identity":1,"labels":["town"],"properties":{"name":"Darjeeling"}},"relationship":{"identity":2,"start":1,"end":0,"type":"trek","properties":{"distance":15,"name":"Darjeeling-Rimbik","winter":"true","summer":"true"}},"end":{"identity":0,"labels":["town"],"properties":{"name":"Rimbik"}}},{"start":{"identity":0,"labels":["town"],"properties":{"name":"Rimbik"}},"relationship":{"identity":3,"start":0,"end":2,"type":"trek","properties":{"distance":18,"name":"Rimbik-BhikeBhanja","winter":"true","summer":"true"}},"end":{"identity":2,"labels":["village"],"properties":{"name":"BhikeBhanja"}}},{"start":{"identity":2,"labels":["village"],"properties":{"name":"BhikeBhanja"}},"relationship":{"identity":4,"start":2,"end":3,"type":"trek","properties":{"distance":4,"name":"BhikeBhanja-Sandakphu","winter":"true","summer":"true"}},"end":{"identity":3,"labels":["peak"],"properties":{"altitude":"12400 ft","name":"Sandakphu"}}}],"length":3}
All parts of this route has property winter set to true, but if I want to add such a condition to my query, I have no results:
MATCH (darjeeling { name: 'Darjeeling' }),(sandakphu { name: 'Sandakphu' }),
paths = allShortestPaths((darjeeling)-[*]-(sandakphu))
WHERE ALL (p IN relationships(paths) WHERE p.winter = true)
RETURN paths
My question is, why the second query retuns no results even though there is a route between A and B, this is the shortest route at all, and all paths on this route has property winter set to true?
Formalizing this into an answer.
Looks like you've got string properties instead of boolean properties. This condition should work for you:
WHERE p.winter = "true"
If you want to change these into boolean properties, you'll need to match on all relationships with this property and use:
SET p.winter = (p.winter = "true")
I believe you need do another MATCH for the paths, like this:
MATCH (darjeeling { name: 'Darjeeling' }), (sandakphu { name: 'Sandakphu' })
MATCH paths = allShortestPaths((darjeeling)-[*]-(sandakphu))
WHERE ALL (p IN relationships(paths) WHERE p.winter = true)
RETURN paths

The urlHelper build wrong path.. What is a rison for this?

I have a route rule as:
routes.MapRoute("HotToursPage",
"HotTours/{countryTo}/{resort}/{param1}/{param2}/{param3}/{param4}/{param5}",
new
{
controller = "HotTours",
action = "Index",
countryTo = UrlParameter.Optional,
resort = UrlParameter.Optional,
param1 = UrlParameter.Optional,
param2 = UrlParameter.Optional,
param3 = UrlParameter.Optional,
param4 = UrlParameter.Optional,
param5 = UrlParameter.Optional
}
);
In the code I have:
var dictionary = new RouteValueDictionary();
aaa.Add("countryTo", countryToInfo.Translit);
aaa.Add("resort", resort);
aaa.Add("param1", param1);
string url = urlHelper.Action("Index", "HotTours", dictionary);
If there are param5, param6 and other, then
url =/hottours/?countryTo=tailand&resort=bangkok&param1=price_from_50000,
but if i remove param5, param6 and other, then all ok:
url =/hottours/tailand/bangkok/price_from_50000
Why if segment count is less then 7, all ok? I need 9 segments, but urlHelper builds wrong url in this case.
When building URLs, you have to provide all of the route values that are in the URL pattern. There is one exception - when the last parameter is optional, you don't need to include it.
Therefore, to consistently deal with segments that could be optional in a long URL pattern, you need more than one route. Each route can only have one UrlParameter.Optional and it must be the right-most segment.
routes.MapRoute("HotToursPage3",
"HotTours/{countryTo}/{resort}/{param1}/{param2}/{param3}/{param4}/{param5}",
new
{
controller = "HotTours",
action = "Index",
param5 = UrlParameter.Optional
}
);
routes.MapRoute("HotToursPage2",
"HotTours/{countryTo}/{resort}/{param1}/{param2}/{param3}",
new
{
controller = "HotTours",
action = "Index",
param3 = UrlParameter.Optional
}
);
routes.MapRoute("HotToursPage1",
"HotTours/{countryTo}/{resort}/{param1}",
new
{
controller = "HotTours",
action = "Index",
param1 = UrlParameter.Optional
}
);
NOTE: I am assuming here that your {countryTo} and {resort} parameters are required. It doesn't seem that sensible to make them optional. However, if I am mistaken, you need another route to deal with those 2 segments being optional or alternatively you should provide sensible default values for them. Generally speaking, if there are no sensible defaults for a value it should be required in the URL.
Do note that you still can only make a segment optional if none of the segments to the right of it are provided. Therefore, this combination will work:
var dictionary = new RouteValueDictionary();
dictionary.Add("countryTo", "test1");
dictionary.Add("resort", "test2");
dictionary.Add("param1", "test3");
var url = Url.Action("Index", "HotTours", dictionary);
But this combination will still build a query string:
var dictionary = new RouteValueDictionary();
dictionary.Add("countryTo", "test1");
dictionary.Add("resort", "test2");
dictionary.Add("param1", "test3");
dictionary.Add("param2", "test4");
dictionary.Add("param5", "test5");
var url = Url.Action("Index", "HotTours", dictionary);
If you want all 5 of your params to be optional (and in any order), you should use query strings, rather than putting them into the path.
routes.MapRoute("HotToursPage",
"HotTours/{countryTo}/{resort}",
new
{
controller = "HotTours",
action = "Index"
}
);
An alternative (that I don't recommend) would be to build up a series of routes that have identifier segments, which allows you to place the values in any order. See ASP.Net MVC Handling Segments with Route.
Nothing like that as you are mentioning below is the main reason
Http.sys service is coded with default maximum of 260 characters per Url segment.
An "Url segment" in this context is the content between "/" characters in the Url. For example:
The max allowed Url segment length can be changed with registry settings:
Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
Value: UrlSegmentMaxLength
Type: REG_DWORD
Data: (Your desired new Url segment maximum allowed length, e.g. 4096)
The maximum allowed value is 32766. If a larger value is specified, it will be ignored.
Restarting the PC is required to make a change to this setting take effect.

Why isn't the value of default-only variable added to an outbound URL as part of the query string?

Why isn't the value of default-only variable myVar added to outbound URL as part of a query string:
routes.MapRoute("MyRoute", "{controller}/{action}",
new { myVar = 1 });
Index.cshtml:
#Html.ActionLink("click me", "CustomVariable", "Home",
new { myVar = 1, newMyVar = 1000 }, null);
From the above routing system generates:
click me
Thank you
In your routing rule you are stating that if the default value is not provided, then use this value.
So there is really no need to provide the value when it is the same as the default value, because it will simply use the default value.

ASP.NET MVC Routing Help Required

I'm creating a online log viewer application which reads logs generated by many applications into a single common database. Log types are error, fatal, debug and I use all to represent all the logs.
I've a controller named AppsController which should server Views for the following requests, where "bi-reports" is one of the many application names we have.
/apps/bi-reports/
/apps/bi-reports/all
/apps/bi-reports/error/
/apps/bi-reports/2011/04/
/apps/bi-reports/2011/04/all
/apps/bi-reports/2011/error
/apps/bi-reports/2011/04/error
/apps/bi-reports/all/last-hundred
/apps/bi-reports/all/most-hundred
/apps/bi-reports/2011/last-hundred
/apps/bi-reports/2011/04/all/last-hundred
How should I configure routes set parameters in Action methods of Controller to get this working?
This is rough idea of your routing definition. I can see that you basically have three types of routes:
routes.MapRoute(
"IrrelevantDates",
"{controller}/{application}/{type}/{range}",
// defaults
new {
controller = "Apps",
action = "UnboundReport",
type = "all",
range = "no-limit"
},
// constraints
new {
type = "apps|error"
}
);
routes.MapRoute(
"RelevantYearOnly",
"{controller}/{application}/{year}/{type}/{range}",
// defaults
new {
controller = "Apps",
action = "YearlyReport",
type = "all",
range = "no-limit"
},
// constraints
new {
year = "19\d{2}|2[01]\d{2}",
type = "apps|error"
}
);
routes.MapRoute(
"RelevantYearAndMonth",
"{controller}/{application}/{year}/{month}/{type}/{range}",
// defaults
new {
controller = "Apps",
action = "MonthlyReport",
type = "all",
range = "no-limit"
},
// constraints
new {
year = "19\d{2}|2[01]\d{2}",
month = "0[1-9]|1[0-2]",
type = "apps|error"
}
);
I've set year constraint to match years between 1900 and 2199, and months so they actually have to specify a valid month 01 to 12.
If you have any additional controllers you will have to define a default route as well and put controller constraint on this one or make controller name static (when just one applies).
I would do something along these lines
''# note, this is untested VB and might need some tweaking.
routes.MapRouteLowercase("Base", "",
New With {.controller = "Home",
.action = "Index",
.year = UrlParameter.Optional,
.paging = UrlParameter.Optional},
New With {.year = "[0-9]*"})
Then your controller would have something like
Function Index(ByVal paging As String, ByVal year As Integer?) As ActionResult
''# do your pre-processing for paging and year.
Return View()
End Function

How to add a constraint to a route parameter?

I'd like to add a constraint to a route parameter that I have. The route pattern is:
{region}/{controller}/{action}
where {region} should only be UK or US.
How can I do this? Is there a regex I can apply here, or some other means of defining this?
This question has been asked before. See:
Constraint Question
In essence, use Regular Expressions:
routes.MapRoute(
"Search", // Route name
"Search/{affiliateId}", // URL with parameters
new { controller = "Syndication", action = "Search" }, // Parameter defaults
new { affiliateId = "SOME REGEX TO TEST GUID FORMAT" } // constraints
);

Resources