Table of Contents
Introduction
This example will implement partial routing for URLs like http://site/News/Sports/TheGame/. In the example the part of the url that is http://site/News/ is the url to a page instance of model type NewsContainer. Then by registering a partial router for ModelType NewsContainer the partial router takes care of routing the remaining part of the url. In the example the partial router will take care of routing the part 'Sports/TheGame/'.
The NewsContent Type
We want to extend routing for content type NewsContainer which look like.
C#
[ContentType]
public class NewsContainer : PageData
{ }
Then we implement a type NewsContent. The class looks like:
C#
public enum NewsCateory
{
Sports,
News,
Economy
}
public class NewsContent
{
public virtual NewsCateory Category { get; set; }
public virtual string Name { get; set; }
public virtual string Body { get; set; }
}
Implementing NewsContentStore
This is an example where NewsContent is stored outside EPiServer CMS (in Dynamic Data Store) therefore we will write a simple store that deliver NewsContent instances. Another option would be to return the routed data as IContent instances. In that case the data could either be delivered through a custom content provider (see section Content Providers) or the data can be stored in EPiServer CMS. Then no provider would be needed instead the data could be loaded/saved through EPiServer.IContentRepository (see section Persisting IContent instances).
In this example we want to partial route URL parts like 'Sports/TheGame/' so we add a method to our store that accepts a category (corrsponds to 'Sports' in URL example) and the name of an article (corresponds to 'TheGame' in URL example). The store implementation look like:
C#
public class NewsContentStore
{
public IOrderedQueryable<NewsContent> News { get { return DynamicDataStoreFactory.Instance.
GetStore(typeof(NewsContent)).Items<NewsContent>(); } }
public NewsContent RouteContent(NewsCateory category, string name)
{
return News.Where(n => n.Category == category
&& n.Name == name)
.SingleOrDefault();
}
}
Implementing IPartialRouter
We want the partial router to be able to handle incoming request beyond pages of type NewsContainer. We also want to be able to create outgoing FURLs for instances of NewsContent. The implementation of the partial router looks like:
C#
public class NewsPartialRouter : IPartialRouter<NewsContainer, NewsContent>
{
private NewsContentStore _newsStore;
private ContentReference _newsContainer;
public NewsPartialRouter(NewsContentStore newsStore, ContentReference newsContainer)
{
_newsStore = newsStore;
_newsContainer = newsContainer;
}
#region RoutePartial
public object RoutePartial(NewsContainer content, SegmentContext segmentContext)
{
NewsContent newsContent = null;
var nextSegment = segmentContext.GetNextValue(segmentContext.RemainingPath);
NewsCateory category;
if (Enum.TryParse<NewsCateory>(nextSegment.Next, out category))
{
nextSegment = segmentContext.GetNextValue(nextSegment.Remaining);
if (!String.IsNullOrEmpty(nextSegment.Next))
{
newsContent = _newsStore.RouteContent(category, HttpUtility.UrlDecode(nextSegment.Next));
if (newsContent != null)
{
segmentContext.RemainingPath = nextSegment.Remaining;
}
}
}
return newsContent;
}
#endregion
#region GetPartialVirtualPath
public PartialRouteData GetPartialVirtualPath(NewsContent content, string language, RouteValueDictionary routeValues, RequestContext requestContext)
{
if (ContentReference.IsNullOrEmpty(_newsContainer))
{
throw new InvalidOperationException("property NewsContainer must be set on start page");
}
return new PartialRouteData()
{
BasePathRoot = _newsContainer,
PartialVirtualPath = String.Format("{0}/{1}/",
content.Category.ToString(),
HttpUtility.UrlPathEncode(content.Name))
};
}
#endregion
}
Registering a Router
Below is the code initialization code that registers the partial router.
C#
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class InitializationModule : IInitializableModule
{
public void Initialize(EPiServer.Framework.Initialization.InitializationEngine context)
{
var startPage = context.Locate.ContentLoader().Get<PageData>(PageReference.StartPage);
var partialRouter = new NewsPartialRouter(new NewsContentStore(), startPage["NewsContainer"] as ContentReference);
RouteTable.Routes.RegisterPartialRouter<NewsContainer, NewsContent>(partialRouter);
NewsContentGenerator.CreateFakeData();
}
public void Preload(string[] parameters)
{
}
public void Uninitialize(EPiServer.Framework.Initialization.InitializationEngine context)
{
}
}
Registering MVC Controllers
In EPiServer CMS you register a MVC controller or WebForm for a Model type by implementing interface EPiServer.Web.IRenderTemplate<TModel>. This is done implicitly if your controller inherits EPiServer.Web.Mvc.PageController<TPage> or EPiServer.Web.Mvc.BlockController<TBlock> or if your WebForm inherits EPiServer.PageBase<TPage>. Below is the code for a Mvc controller for NewsContent and NewsContainer.
C#
public class NewsContentController : System.Web.Mvc.Controller, IRenderTemplate<NewsContent>
{
public ActionResult Index()
{
var newsContent = Request.RequestContext.GetRoutedData<NewsContent>();
return View(newsContent);
}
}
C#
public class NewsContainerController : PageController<NewsContainer>
{
public ActionResult Index()
{
var newsStore = new NewsContentStore();
return View(newsStore.News.ToList());
}
}
Creating MVC Views
To display a single news from the above controller we create a view located as /Views/NewsContent/index.aspx. We also create a view for the NewsContainer class that lists all news with partial routed FURLs. The below code is the code for the views.
C#
<%@ Page Title="" Language="C#"
Inherits="System.Web.Mvc.ViewPage<CodeSamples.Additional_Content.HowTo.PartialRouting.NewsContent>" %>
<h2><%=Model.Name%></h2>
<p><%=Model.Body %></p>
C#
<%@ Page Title="" Language="C#"
Inherits="System.Web.Mvc.ViewPage<List<CodeSamples.Additional_Content.HowTo.PartialRouting.NewsContent>>" %>
<%@ Import Namespace="System.Web.Routing" %>
<%@ Import Namespace="EPiServer.Web.Routing" %>
<h2>List of news</h2>
<ul>
<%foreach (var news in Model) {%>
<li>
<a href="<%=RouteTable.Routes.GetVirtualPathForPartialRouted(news, null).GetUrl()%>"><%=news.Name%></a>
</li>
<%}%>
</ul>
Creating Outgoing URLs
To create an outgoing url for a NewsContent item you can call the extension method GetVirtualPathForPartialRouted<T>(object routedData, string language) on RouteCollection (the extension method is located in namespace EPiServer.Web.Routing). For IContent instances it is also possible to call method GetVirtualPath(ContentReference contentLink, string language) or in web forms create a link in the html like '/Templates/NewsContent.aspx?id=7__news' then the FURL module will call the partial router during outgoing parsing to create an FURL for the content. Below is an example of how outgoing FURLs can be constructed.
C#
NewsContent news = GetNewsContent();
var furl = RouteTable.Routes.GetVirtualPathForPartialRouted(news, null).GetUrl();
IContent iContent = GetIContent();
var anchor = new System.Web.UI.HtmlControls.HtmlAnchor();
anchor.HRef = "/templates/NewsContent.aspx?id=" + iContent.ContentLink.ToString();
Creating NewsContent
In this example we show how data stored outside EPiServer CMS can be routed to. In this example we use DynamicDataStore to store our NewsContent. The follow code creates some NewsContent instance and store them in DynamicDataStore.
C#
public class NewsContentGenerator
{
public static void CreateFakeData()
{
var newsContentStore = DynamicDataStoreFactory.Instance.GetStore(typeof(NewsContent));
if (newsContentStore == null)
{
newsContentStore = DynamicDataStoreFactory.Instance.CreateStore(typeof(NewsContent));
var soccerNews = new NewsContent()
{
Category = NewsCateory.Sports,
Name = "Sweden",
Body = "Sweden have qualified for EURO 2012 championship in soccer"
};
newsContentStore.Save(soccerNews);
var olymicNews = new NewsContent()
{
Category = NewsCateory.Sports,
Name = "Olympic",
Body = "The next summer olympic will take place in London"
};
newsContentStore.Save(olymicNews);
var euroNews = new NewsContent()
{
Category = NewsCateory.Economy,
Name = "Euro",
Body = "The euro has reached new levels"
};
newsContentStore.Save(euroNews);
var oilNews = new NewsContent()
{
Category = NewsCateory.Economy,
Name = "Oil",
Body = "New oil findings have been made in the artic"
};
newsContentStore.Save(oilNews);
var politicNews = new NewsContent()
{
Category = NewsCateory.News,
Name = "Selection",
Body = "Sweden have selected a new government"
};
newsContentStore.Save(politicNews);
var earthQuakeNews = new NewsContent()
{
Category = NewsCateory.News,
Name = "Eartquake",
Body = "An earthquake was registered this morning"
};
newsContentStore.Save(earthQuakeNews);
}
}
}
See Also
- In the Relate template package you can see an implementation of partial routing for blogs and blog entries.
- In the section Content Providers you will find more information on how to create content providers.
- In the SDK framework reference you will find more information on the EPiServer.Web.Routing.IPartialRouter<TIncoming, TOutgoing> and base class.
Do you find this information helpful? Please log in to provide feedback.