URL without Index

Member since: 2010

Hi, guys,

If I have a pager on the page, is there a possibility to ditch the Index in the URL by defining a custom route, ie have localhost:12345/Events/2 instead of localhost:12345/Events/Index/2

Thank you in advance,

Marija

 

#65637 Feb 04, 2013 14:52
  • Member since: 2004

    What you need to do is to replace the segment that handles {action}. By default {action} is handled by ParameterSegment which always will consume the current segment form the url. In your case you would like the segment handling action that it does not consume the segment but instead passes it on to next segment like {page} that handles paging.

    So you need a different segment implementation that could look something like:

    public class OptionalActionSegment : ParameterSegment
    {
    private IContentLoader _contentLoader;

    public OptionalActionSegment(string name, IContentLoader contentLoader)
    :base(name)
    {
    _contentLoader = contentLoader;
    }

    public override bool RouteDataMatch(SegmentContext context)
    {
    var segmentPair = context.GetNextValue(context.RemainingPath);
    if (!string.IsNullOrEmpty(segmentPair.Next))
    {
    if (IsRequestForEventPage(context))
    {
    //do not consume segment just add default action
    context.RouteData.Values[Name] = context.Defaults[Name];
    }
    else
    {
    context.RouteData.Values[Name] = segmentPair.Next;
    context.RemainingPath = segmentPair.Remaining;
    }

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

    return false;
    }

    private bool IsRequestForEventPage(SegmentContext context)
    {
    IContent content = _contentLoader.Get<IContent>(context.RoutedContentLink);
    return content is EPiServer.Templates.AlloyTech.PageTypes.EventItemPage;
    }
    }

     

    Then you can register a route with your segment as:

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

    var segment = new OptionalActionSegment("action", ServiceLocator.Current.GetInstance<IContentLoader>());
    var routingParameters = new MapContentRouteParameters()
    {
    SegmentMappings = new Dictionary<string, ISegment>(),
    UrlSegmentRouter = new DefaultUrlSegmentRouter(ServiceLocator.Current.GetInstance<IContentLoader>(),
    new LanguageSelectorFactory(), ContentReference.StartPage, ServiceLocator.Current.GetInstance<IRoutingSegmentLoader>())
    };
    routingParameters.SegmentMappings.Add("action", segment);

    routes.MapContentRoute(
    name: "optionalaction",
    url: "{language}/{node}/{partial}/{action}/{page}",
    defaults: new { action = "index" },
    parameters: routingParameters);
    }

     

    in your controller you can then get the paging value from RouteValues on Request context where it will be stored with key "page" (if that is the name of your pagining segment).

    #65671 Feb 05, 2013 12:46
  • Member since: 2010

    Thanks a lot for such a detailed answer! I will try this out, hopefully it will go smoooothly :)

     

    // Edit: tried it, went smoothly :)

    #65675 Edited, Feb 05, 2013 13:41
  • Member since: 2010

    Hi, Johan, 

    Is there any other place I could register routes?

    ServiceLocator.Current.GetInstance<IContentLoader>() gives me StructureMap exception when I call it in Global.asax. (I am using StructureMap in the solution, too)

    #73036 Jul 04, 2013 14:43
  • Member since: 2010

    I have fixed it finally, simply by adding an if statement before using IContentLoader and IRoutingSegmentLoader.

    The code is now:

    protected override void RegisterRoutes(RouteCollection routes)
            {
                base.RegisterRoutes(routes);
                            
                IContentLoader contentLoader;
                ServiceLocator.Current.TryGetExistingInstance(out contentLoader);
    
                IRoutingSegmentLoader routingSegmentLoader;
                ServiceLocator.Current.TryGetExistingInstance(out routingSegmentLoader);
    
                if (contentLoader != null && routingSegmentLoader != null)
                {
                    var segment = new OptionalActionSegment("action", contentLoader);
                    var routingParameters = new MapContentRouteParameters()
                    {
                        SegmentMappings = new Dictionary<string, ISegment>(),
                        UrlSegmentRouter = new DefaultUrlSegmentRouter(
                            contentLoader,
                            new LanguageSelectorFactory(),
                            ContentReference.StartPage,
                            routingSegmentLoader)
                    };
                    routingParameters.SegmentMappings.Add("action", segment);
    
                    routes.MapContentRoute(
                        name: "optionalaction",
                        url: "{language}/{node}/{partial}/{action}/{page}",
                        defaults: new { action = "index" },
                        parameters: routingParameters);
                }
            }

        

    #73467 Jul 23, 2013 14:31