The value will be in the RouteData under the username
key, but it won't be mapped to the parameter named username
automatically, because the key isn't a known route value containing that parameter name.
You can create a route just for this method:
routes.MapRoute(
name: "userProfileByUsername",
template: "Account/UserProfile/{username}"),
defaults: new { controller = "Account", action = "UserProfile" });
But that would be nonsense, as it would require creating a route for every action method. When a pattern of multiple uses for a single route emerges, it pays off to create a route like this, because it saves you from having to declare the same attribute multiple times.
For example when you want to declare multiple action methods in one controller:
/Account/UserProfile/{username}
/Account/View/{username}
/Account/Foo/{username}
/Account/Bar/{username}
Then it would be smart to create a new route instead:
routes.MapRoute(
name: "accountActionByUsername",
template: "Account/{action}/{username}"),
defaults: new { controller = "Account" });
For a one-off case, or when the pattern differs per action method, you could use attribute routing to opt-in to specific routes:
[HttpGet("[action]/{username}")]
public IActionResult UserProfile(string username)
Note the use of the new [action]
placeholder, so you won't have to have your action name in a string anymore.
Or you could find the value by accessing the raw route data, but you really shouldn't:
public IActionResult UserProfile()
{
string username = ViewContext.RouteData.Values["username"];
// ...
}
Finally you could opt to have the username be a query string parameter:
public IActionResult UserProfile([FromQuery]string username)
Making the request URL /Account/UserProfile?username=MyUsername
.