Partial Routing with Episerver 7 and Web Forms
Saw this post on Episerver World about routing and friendly URLs and in that case external data. I had done something similar so I simplified and extracted into an Alloy project.
Joel's post about routing was a great starting point for me.
Some example data:
namespace EPiServer.Templates.Alloy.Models
{
using System.Collections.Generic;
public class ItemRepository
{
public static List<Item> GetAll()
{
return new List<Item>
{
new Item { Id = 458, Title = "Example item", UrlName = "example-item" },
new Item { Id = 500, Title = "Funky item", UrlName = "funky" },
new Item { Id = 899, Title = "Test item with id 899", UrlName = "this-is-an-awesome-urlname" }
};
}
public class Item
{
public int Id { get; set; }
public string Title { get; set; }
public string UrlName { get; set; }
}
}
}
I then created to really simple page types, ItemPage and ItemListPage. I wanted to use the listing page's URL name as the first part of all "Item" custom friendly names. Therefore I published the pages like this:
The listing page repeater:
<asp:Repeater runat="server" ID="ItemsRepeater"
ItemType="EPiServer.Templates.Alloy.Models.ItemRepository.Item">
<ItemTemplate>
<%--We could attach a custom UrlRewriter but it's easier to just output
the custom friendly URL by hand like this--%>
<h2><a href="./<%#: Item.UrlName%>/"><%#: Item.Title%></a></h2>
</ItemTemplate>
</asp:Repeater>
Code-behind for the list page including the partial router and router registration:
namespace EPiServer.Templates.Alloy.Views.Pages
{
using System.Linq;
using System.Web.Routing;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Templates.Alloy.Models;
using EPiServer.Templates.Alloy.Models.Pages;
using EPiServer.Web.Routing;
using EPiServer.Web.Routing.Segments;
public partial class ItemListPageTemplate : SiteTemplatePage<ItemListPage>
{
protected override void OnLoad(System.EventArgs e)
{
base.OnLoad(e);
ItemsRepeater.DataSource = ItemRepository.GetAll();
ItemsRepeater.DataBind();
}
public class ItemListPageRouter : IPartialRouter<ItemListPage, ItemPage>
{
public object RoutePartial(ItemListPage content, SegmentContext segmentContext)
{
var nextSegment = segmentContext
.GetNextValue(segmentContext.RemainingPath);
var urlSegment = nextSegment.Next;
if (string.IsNullOrEmpty(urlSegment))
{
return null;
}
ItemRepository.Item item = ItemRepository
.GetAll()
.FirstOrDefault(x
=> x.UrlName.Equals(urlSegment));
if (item == null)
{
return null;
}
segmentContext.RemainingPath = nextSegment.Remaining;
// Get the child page that can present a full single item
segmentContext.RoutedContentLink =
DataFactory
.Instance
.GetChildren<ItemPage>(content.PageLink)
.First()
.PageLink;
// Put the item's id in segment context
segmentContext.SetCustomRouteData("itemid", item.Id);
return null;
}
public PartialRouteData GetPartialVirtualPath(ItemPage content,
string language, RouteValueDictionary routeValues,
RequestContext requestContext)
{
return new PartialRouteData();
}
}
[ModuleDependency(typeof(Web.InitializationModule))]
public class ItemListPageRouterInitialize : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
RouteTable.Routes.RegisterPartialRouter(
new ItemListPageRouter());
}
public void Uninitialize(InitializationEngine context)
{
}
public void Preload(string[] parameters)
{
}
}
}
}
The item page:
<h1><%: Item.Title %></h1>
<dl>
<dt>Id</dt>
<dd><%: Item.Id %></dd>
<dt>Friendly name</dt>
<dd><%: Item.UrlName %></dd>
</dl>
The item page code-behind:
namespace EPiServer.Templates.Alloy.Views.Pages
{
using System.Linq;
using EPiServer.Templates.Alloy.Business;
using EPiServer.Templates.Alloy.Models;
using EPiServer.Templates.Alloy.Models.Pages;
using EPiServer.Web.Routing;
public partial class ItemPageTemplate : SiteTemplatePage<ItemPage>
{
protected Models.ItemRepository.Item Item { get; set; }
protected override void OnLoad(System.EventArgs e)
{
base.OnLoad(e);
int itemId = Request.RequestContext.GetCustomRouteData<int>("itemid");
this.Item = ItemRepository.GetAll().SingleOrDefault(x => x.Id == itemId);
if (this.Item == null)
{
this.Item = new ItemRepository.Item { Title = "No Matching Item Not Found" };
}
}
}
}
The result, notice the URLs:
Published and tagged with these categories: Episerver, ASP.NET