科技动态

Market routing in Episerver Commerce

微信扫一扫,分享到朋友圈

Market routing in Episerver Commerce

The most of the Episerver Commerce project examples (for example, Quicksilver
) are using cookies to store selected market. The URL doesn’t change which can cause several SEO issues. Crawlers are not able to index market specific content. If the market info could be included in the URL, it would solve most of these problems.

The solution to this problem is not trivial. There are some great articles about custom routing in Episerver
Custom routing for EPiServer content
and Episerver segments explained, registering custom routes in Episerver
. But these articles do not have a complete solution for the market routing.

I wanted to make URLs to look like this: http://mysite.com/en/europe/products
, where europe
is a market ID.

The first task is to create a special segment for the market.

public class MarketSegment : SegmentBase
{
    private readonly IMarketService _marketService;
    private readonly ICurrentMarket _currentMarket;

    public const string SegmentName = "market";

    public MarketSegment(IMarketService marketService, ICurrentMarket currentMarket)
        : base(SegmentName)
    {
        if (marketService == null) throw new ArgumentNullException(nameof(marketService));
        if (currentMarket == null) throw new ArgumentNullException(nameof(currentMarket));
        _marketService = marketService;
        _currentMarket = currentMarket;
    }

    public override bool RouteDataMatch(SegmentContext context)
    {
        var segmentPair = context.GetNextValue(context.RemainingPath);
        var marketCode = segmentPair.Next;

        if (!string.IsNullOrEmpty(marketCode))
        {
            return ProcessSegment(context, segmentPair);
        }

        if (context.Defaults.ContainsKey(Name))
        {
            context.RouteData.Values[Name] = context.Defaults[Name];
            return true;
        }

        return false;
    }

    public override string GetVirtualPathSegment(RequestContext requestContext, RouteValueDictionary values)
    {
        var contentLink = requestContext.GetRouteValue("node", values) as ContentReference;
        if (ContentReference.IsNullOrEmpty(contentLink)) // Skips for non-content items.
        {
            return null;
        }

        var currentMarket = _currentMarket.GetCurrentMarket();
        return currentMarket.MarketId.Value.ToLower();
    }

    private bool ProcessSegment(SegmentContext context, SegmentPair segmentPair)
    {
        var marketCode = segmentPair.Next;
        var marketId = new MarketId(marketCode);
        var market = _marketService.GetMarket(marketId);
        if (market == null) return false;

        context.RouteData.Values[Name] = marketCode;
        context.RemainingPath = segmentPair.Remaining;

        _currentMarket.SetCurrentMarket(marketId);

        return true;
    }
}

Here the market segment inherits from the SegmentBase
class which provides default behavior. You have to override two methods – RouteDataMatch
and GetVirtualPathSegment
.

The RouteDataMatch
method is used for URL interpretation – here you check if your segment is found in the URL and do the actions based on the segment value. Here I am getting the next segment value which should be my market segment. The next segment depends on already parsed segments. As the first segment is used for language, the second one will be the market segment. If the segment has value, I am trying to interpret it. I am just checking if the market with such code exists. If it does, then I am setting the current market value. Additionally, I am adding market info to the RouteData
.

The GetVirtualPathSegment
method is used to generate URL of content. Here you provide the value for your segment in the URL. In my case, it is checking if the content is Episerver
content and then returns a current market ID value. This value then will be presented in the URLs.

The next step requires some “hacking.” I have to register my custom segment with a custom content route. But I must put it before any default Episerver
route. Otherwise, it will not be picked. By default, Episerver
has only one extension method for adding content routes – MapContentRoute
. It appends the route at the end. So I have created an extension method to insert route at any position. I will not list it here as it is quite long, but you can find it on Github
.

Now register the segment and the custom route.

public static void MapMarketSegment(this RouteCollection routes)
{
    var segment = new MarketSegment(MarketService, CurrentMarket);
    var segmentMappings = new Dictionary { { MarketSegment.SegmentName, segment } };
    var parameters = new MapContentRouteParameters
    {
        Direction = SupportedDirection.Both,
        SegmentMappings = segmentMappings
    };
    routes.InsertAndMapContentRoute(
        index: routes.IndexOf("pages"),
        name: MarketSegment.SegmentName,
        url: "{language}/{market}/{node}/{partial}/{action}",
        defaults: new { action = "index" },
        parameters: parameters);
}

public static int IndexOf(this RouteCollection routes, string name)
{
    var defaultRoute = routes
        .Select(r => r as DefaultContentRoute)
        .Where(x => x != null)
        .First(x => x.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
    return routes.IndexOf(defaultRoute);
}

First, create a market segment and provide all the necessary services to it. Then create content route parameters with our segment. The last step is inserting the new content route. I have added it before the pages
route which is the default route for Episerver
content.

The last step is calling this MapMarketSegment
in the Global.asax.cs
on RegisterRoutes
. Make sure to call it after base route registration.

protected override void RegisterRoutes(RouteCollection routes)
{
    base.RegisterRoutes(routes);

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { action = "Index", id = UrlParameter.Optional });

    RouteTable.Routes.MapMarketSegment();
}

Now, you should be able to see markets in the URL and change the market by changing the market ID in the URL.

I have created an example project based on the Quicksilver. The project is available on Github
.

第二十四节MySQL

上一篇

美媒:不是亚马逊和微软 阿里云成全球云计算增长之王

下一篇

你也可能喜欢

评论已经被关闭。

插入图片

热门栏目

Market routing in Episerver Commerce

长按储存图像,分享给朋友