Summer of Code: Update to the Mapped Page Provider
A lesson I’ve learned the hard way is that being product manager for a product like EPiServer CMS with thousands of dedicated developers and editors, your life tend to get rather busy. At least mine does. Dozens of meetings, presentations, customer interviews, conferences, requirement docs and an obscene amount of travel days. And although it can be both rewarding and fun it’s not always as glamorous as it sounds . This means that it’s been difficult to do all my usual “fun stuff” like coding open source projects and blogging about it – and I’ve sadly had to watch my status on the “Top Bloggers” board on EPiServer World go down. Obviously, I can’t have that – so in the hope that July means “Swedes are out of the office on strangely long vacations and I won’t be all that busy product manager’ing” I’ll now declare it the “Summer of Code” and start pushing out a series of blog posts with a lot of small goodies that I’ve had in mind for a long time. If you like me find yourself with a little time on your hand this July, bring your laptop out into the sun, fire up Visual Studio and join the Summer of Code. I’ll buy a cold beer to anyone who launches a cool, useful – and easily installable – module for EPiServer CMS this July. Don’t make me drink all the beers myself.
Todays’ effort included upgrading the Mapped Page Provider project to take advantage of the Dynamic Data Store – and wrap it in a nice little NuGet Package.
As you might recall, the Mapped Page Provider is a new base class to use when creating custom page providers, that makes it a lot easier to expose an existing data source as pages in the CMS. With the Mapped provider you don’t need to deal with all the nitty-gritty of Guids, ID’s, Urls, etc yourself – but rather just connect string-keys with home-brewed page-data objects.
A little while ago I was playing around trying to make a little source-code-browser (which might eventually be available if I manage to get the right political buy-in for it) and it seemed natural to expose the source-code copied to a VPP through a PageProvider in order to get nice looking urls – and easy navigation through the source. Using the Mapped Provider it didn’t take long to turn a VPP with source files into a PageTree in the CMS:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EPiServer.Core;
using EPiServer.Research.PageProviders;
using EPiServer.Web.Hosting;
using System.Web.Hosting;
using System.IO;
namespace SourceCodeBrowser.PageProvider
{
//A read-only page provider for source code - Browse either by file or by classes
public class CodePageProvider : MappedPageProvider
{
protected static string rootpath = "/SourceCodeBrowser/Source/";
protected static string[] allowedext = {".cs",".aspx",".ascx",".config",".js",".css" };
protected override List<string> GetRootChildren()
{
//List Vpp root folder
return GetChildren(rootpath);
}
protected override List<string> GetChildren(string Key)
{
//List children under a given VPP root
//Leaf or not
if (Key.EndsWith("/"))
{
var dir=VirtualPathHandler.Instance.GetDirectory(Key, true);
var rt = dir.Directories.Cast<VirtualFileBase>().Select(vfb => vfb.VirtualPath).ToList();
rt.AddRange(dir.Files.Cast<VirtualFileBase>()
.Where(vfb => allowedext.Contains(
VirtualPathUtility.GetExtension(vfb.VirtualPath.ToLower()))).Select(vfb => vfb.VirtualPath).ToList());
return rt;
}
else return new List<string>();
}
protected override PageData GetPage(string Key)
{
PageData pd = new PageData();
//Identify parent
string parent = null;
if(Key!=rootpath) parent=VirtualPathUtility.GetDirectory(Key.TrimEnd('/'));
if (parent == rootpath) parent = null;
string nm=VirtualPathUtility.GetFileName(Key);
InitializePageData(pd, Key, nm ?? Key, parent);
if (Key.EndsWith("/"))
{
//Folder
}
else
{
//File
//Load file contents into property
var f=VirtualPathHandler.Instance.GetFile(Key, true) as NativeFile;
StreamReader read = new StreamReader(f.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read));
pd.SetValue("Code", read.ReadToEnd().Replace("<","<").Replace(">",">"));
pd.SetValue("CodeType", VirtualPathUtility.GetExtension(Key).TrimStart('.'));
read.Close();
pd.SetValue("PageStartPublish", f.Changed);
}
return pd;
}
protected override string GetPageType(string Key)
{
return (Key.EndsWith("/")) ? "FolderPageType" : "CodePageType";
}
}
}
Summer of code
Other things lined up for this month (if time permits):
- New NuGet version of the QuickWatchGadget (with dynamic code-execution)
- A bunch of new Criteria for the CriteriaPack – including an XForms Criterion
- Update to the MobilePack – maybe it’s time for v.1.0
- Sharing some of the code I demoed at the US Partner Summit – like the Twitter Integration
- A few new gadgets might also find their way to this blog
- And a bunch of ‘secret’ stuff that I don’t want to share just yet
Happy summer everybody!
Looking forward to your new blog posts :)