A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Allan Thraen
Jul 4, 2011
  6139
(2 votes)

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 Smile. 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("<","&lt;").Replace(">","&gt;"));
                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 Smile

 

Happy summer everybody!

Jul 04, 2011

Comments

Fredrik Josefsson
Fredrik Josefsson Jul 5, 2011 10:02 AM

Looking forward to your new blog posts :)

Please login to comment.
Latest blogs
Building simple Opal tools for product search and content creation

Optimizely Opal tools make it easy for AI agents to call your APIs – in this post we’ll build a small ASP.NET host that exposes two of them: one fo...

Pär Wissmark | Dec 13, 2025 |

CMS Audiences - check all usage

Sometimes you want to check if an Audience from your CMS (former Visitor Group) has been used by which page(and which version of that page) Then yo...

Tuan Anh Hoang | Dec 12, 2025

Data Imports in Optimizely: Part 2 - Query data efficiently

One of the more time consuming parts of an import is looking up data to update. Naively, it is possible to use the PageCriteriaQueryService to quer...

Matt FitzGerald-Chamberlain | Dec 11, 2025 |

Beginner's Guide for Optimizely Backend Developers

Developing with Optimizely (formerly Episerver) requires more than just technical know‑how. It’s about respecting the editor’s perspective, ensurin...

MilosR | Dec 10, 2025