I was wondering if you could show me all the various ways to declare routes in ASP.NET MVC (1 and 2). Please explain each method of defining a route, how it is used, and what case it covers.
Here is an example of what I am hoping to collect here:
routes.MapRoute("Directors",
"Directors/{filter}/{skip}",
new { controller = "Directors", action = "Index", skip = 0, filter = "" },
new { skip = #"\d+", filter = #"^[a-zA-Z]+.+" });
Directors = the name of the route. Directors/{filter}/{skip} = the url definition. new { controller = "Directors", action = "Index", skip = 0, filter = "" } = the default for this route. new { skip = #"\d+", filter = #"^[a-zA-Z]+.+" } = the constraints for this route.
My first port of call would be the ASP.NET learning pages on routing.
I think this may also be a good use of the Community Wiki feature, as the question you're asking a pretty vague question where there are not real answers, just good documentation on routes.
Related
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¶m1=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.
I have a MVC application for users to make requests, database schema something like this:
Request(RequestID, RequestType,...)
CarKey(CarKeyID, RequestID,...)
DoorKey(DoorKeyID, RequestID,...)
CarKey and DoorKey are different request types.
Let's say I have one CardKey request with a RequestID = 10, CarKeyID = 3, one DoorKey request with a RequestID = 11 and DoorKeyID = 4
My search result page shows all the requests with links like this:
http://localhost/Requests/10
When user click on this link, since it's a CarKey request, how do I route it to my CarKey controller's Edit action with RequestID = 10 or CarKeyID = 3 ?
After doing some research, I found this is very useful:
RedirectToAction with parameter
So What I did was to change return type in my RequestsController's Details action to
var carKeyID = request.CarKeys.First().CarKeyID;
return RedirectToAction("Edit","CarKeys", new { id = carKeyID});
It seems all the examples I can find use a ViewModel for some reason, so a MVC and not MVVM answer is what I'm looking for :)
Controller
List<PermOptions> have = new List<PermOptions>();
List<PermOptions> nothave = new List<PermOptions>();
...populate the lists here...
var set = new PermissionSet
{
ExtId = extid,
HaveList = have,
NotHaveList = nothave
};
return View(set);
View
#model path.to.model.PermissionSet
#{
var NotHave = new MultiSelectList(Model.NotHaveList, "Id", "Role");
}
#Html.ListBoxFor(model => model.NotHaveList, NotHave, new { #size = "30", id = "possible" });
#{
var Have = new MultiSelectList(#Model.HaveList, "Id", "Role");
}
#Html.ListBoxFor(model => model.HaveList, Have, new { #size = "30", id = "have" });
Everything works just fine displaying the initial lists and moving items, but when I submit the form the ListBoxFors are part of to the Post action, PermissionSet.HaveList and PermissionSet.NotHaveList are empty with a zero count. Thinking it was a select issue or format of return issue, I added javascript to select all the items in both boxes, and in the browser debug pane I can see that there are values in the submitted Form data that match up to various option values for NotHave and Have, but if in the Post action, I make a call to ViewData["NotHave"], it is also reporting empty.
What do I need to do to get the list of items in each ListBoxFor in my Post controller, preferrably as part of PermissionSet?
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
I thought this was going to be straight forward but I managed to hose it up some how. If I want to pass URL parameters to another action do I have to create a new route for that?
controller
[ChildActionOnly]
public ActionResult ContentSection(string sectionAlias, string mvcController, string mvcAction = null)
view
#Html.RenderAction("ContentSection", "Portal", new {sectionAlias = "TermsAndConditions", mvcController = "Portal", mvcAction = "ChoosePayment"})
error
CS1502: The best overloaded method match for 'System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)' has some invalid arguments
The problem here is that
#Html.RenderAction("ContentSection", "Portal", new {sectionAlias = "TermsAndConditions", mvcController = "Portal", mvcAction = "ChoosePayment"})
Is the equivalent to
<%= Html.RenderAction("ContentSection", "Portal", new {sectionAlias = "TermsAndConditions", mvcController = "Portal", mvcAction = "ChoosePayment"}) %>
In the the Webforms ViewEngine (which is also the same a Response.Write). Since RenderAction returns void, you cannot Response.Write it. What you want to do is this:
#{
Html.RenderAction("ContentSection", "Portal", new {sectionAlias = "TermsAndConditions", mvcController = "Portal", mvcAction = "ChoosePayment"});
}
The #{ } syntax signifies a code block in the Razor view engine, which would be equivalent to the following the the Webforms ViewEngine:
<% Html.RenderAction("ContentSection", "Portal", new {sectionAlias = "TermsAndConditions", mvcController = "Portal", mvcAction = "ChoosePayment"}); %>
The short answer is to use #Html.Action() like this:
#Html.Action("ContentSection", "Portal", new {sectionAlias = "Terms", ...})
The long answer was already given by Nathan Anderson.
P.S. Credit for this answer really goes to James Nail, who posted it as a comment in Nathan's answer, but I found it so easy and valuable that I thought it should be an individual answer.