When you use MapContentRoute it will treat the parts of the url that are inside {} as segment (something that is implementing EPiServer.Web.Routing.Segments.ISegment). There are some predefined keys that are handled by default, e.g. {node} that is a content instance, {language} that handles language segment. {uid} however will not be recognized and thereby it will be handled as a ParameterSegment.
So in your case you should use {language} instead of {languageBranch).
A parameter segment works in the way that during incoming routing the value of the segment will be placed in RequestContext.RouteData.Values with the parameter name as key, in your case "uid". During creation of outgoing links the parameter will output value if the key (e.g "uid") is part of RouteValues dictionary.
You can also have your own custom ISegment implementation (instead of ParameterSegment) that handles your segment, Then you need to use the overload of MapContentRoute that takes a ContentParameters as parameter and in property SegmentMappings add your custom segment with your url pattern as key as e.g. contentParameters.SegmentMappings.Add("uid", customSegmentInstance)
So what would be the best way to direct the url to a specific EPiServer page? Writing a custom iSegment implementation for the {node} segment?
I do not think any of the built in segements will do what you want so you need to create your own segment like UserIdSegment (it should be fairly simple, there is a baseclass SegmentBase that you can use). You could e.g. pass in the contentreference of the page in the constructor to your segment. And in RouteDataMatch check if the incoming segment match the a user id and if so set RoutedContentLink. Something like:
public class UserIdSegment : SegmentBase
{
private ContentReference _linkToProfilePage;
public UserIdSegment(string name, ContentReference contentLink) : base(name)
{
_linkToProfilePage = contentLink;
}
public override string GetVirtualPathSegment(System.Web.Routing.RequestContext requestContext, System.Web.Routing.RouteValueDictionary values)
{
return null;
}
public override bool RouteDataMatch(SegmentContext context)
{
var segmentPair = context.GetNextValue(context.RemainingPath);
if (IsValidUserId(segmentPair.Next))
{
context.RemainingPath = segmentPair.Remaining;
context.RoutedContentLink = _linkToProfilePage;
return true;
}
return false;
}
private bool IsValidUserId(string p)
{
//Here should logic for user id go
}
}
The you can register your route something like:
var segment = new UserIdSegment("uid", new ContentReference(2424));
var routingParameters = new MapContentRouteParameters()
{
SegmentMappings = new Dictionary<string, ISegment>()
};
routingParameters.SegmentMappings.Add("uid", segment);
routes.MapContentRoute(
name: "userprofiles",
url: "user/{uid}/{language}/{action}",
defaults: new { action = "index" },
parameters: routingParameters);
In case someone reads this in the future I wrote an article on the topic of custom routing featuring, amongst other things a custom segment inspired by Johan's above.
Maybe I'm missing something here, but I've set up a custom route using a custom segment, and the route parameter I'm really concerned about always is null in my controller. For example, if I use the example above, the 'uid' parameter will be null in the page controller for the profile page. I can see it fine if I pass it as a querystring, but that defeats the purpose. What am I missing?
Chris, I got the same problem but changed the code for RouteDataMatch to this,
----------
public override bool RouteDataMatch(SegmentContext context)
{
var segmentPair = context.GetNextValue(context.RemainingPath);
var userId = segmentPair.Next;
if (IsValidUserId(userId))
{
context.RemainingPath = segmentPair.Remaining;
context.RoutedContentLink = _linkToProfilePage;
context.RouteData.Values.Add("uid", userId);
return true;
}
return false;
}
----------
e.g. adding the value to the RouteData object. Don't know if this is the correct way to do it but it works :)
/Viktor
Hi I created a custom episerver route in Global.asax
RouteTable.Routes.MapContentRoute("UserProfileRoute", "user/{uid}/{languageBranch}/{node}/{partial}/{action}", new
{
uid = "",
languageBranch = "en",
node = "2424",
partial = UrlParameter.Optional,
action = UrlParameter.Optional
});
the idea of this route is when i open the following link "www.mywebsite.com/user/123123" it should open the Userprofile episerver page with id "2424"
but with the above mention url it takes me to startpage instead which has a id 3.
what am i doing wrong in this scenrio??
the second problem i am having is when i change the language in the url it never change the langiage of the page e.g "www.mywebsite.com/user/123123/fr" it still stay english