Mark Everard

Hello, I'm Mark – a PhD physicist turned technologist / architect.

Archive for August, 2010

Editor access to EPiServer Admin functionality

with 3 comments

EPiServer separates the functionality it offers website editors and site administrators by using two distinct user interfaces (edit and admin mode). Edit mode offer further granular control by allowing you to set access rights over content such as files, pages (and also page types in CMS6).

However there are times when you may wish to provide editor access to a particular admin functionality, without providing full access to the admin interface. Out-of-the-box EPiServer doesn’t support this. Access to the admin mode is defined via a location path configuration set in web.config, which by default only gives access to users in the WebAdmins and the Administrators role. There is no functionality to provide further granular access to any particular function within the admin interface.

However there are a few routes available to allow us to meet this requirement.

  1. If using CMS6, create a dashboard gadget to provide the required admin functionality.
  2. Use Reflector to inspect the EPiServer assemblies so you can recreate the required functionality in a page that lives on a different path and so will not be subject to the predefined admin interface’s location security configuration (following the technique shown by David Knipe).

Whilst both of the above will allow us to meet our needs, neither are particular elegant as they both involve ‘reinventing the wheel’ and recreating the necessary admin functionality at another position in our codebase. This ultimately leads to a solution that will be harder to maintain.

Ideally what we want is a way of using the existing EPiServer functionality and interface but providing access to a specific admin function to a user in a non-Admin role.

Enter the VirtualPathMappedProvider……

The solution below uses the VirtualPathMappedProvider to map an existing admin functionality (.aspx page) to a developer-defined virtual url, which is subjected to different location security configuration. This is made possible by the fact that the EPiServer admin pages (or the ones I’ve looked at) rely solely on the location path element for their security and do no further on-page access checking (which is as it should be really). Once you’ve bypassed the first security checkpoint – you’ve got a free run.

I’m going to provide access to the Category administration interface to any user in a newly-created role that I’ll call CategoryAdmins.  Category administration is often a function that in my opinion falls more under the remit of an Editor, though that does depend on your EPiServer implementation (as categories can be used for a lot more than just labelling).

  • Add Mapped links – create a virtual path mapping in episerver.config (or in web.config pre-CMS 6) which forwards the defined virtual url to the existing categories.aspx page. You will need to provide a mapping for every page that you want to allow access to. Category administration is handled by a single .aspx page.
<add name="AdminMappings" type="EPiServer.Web.Hosting.VirtualPathMappedProvider,EPiServer" />
<virtualPathMappings>
   <add url="~/ui/CMS/CategoryAdmin/Categories.aspx" mappedUrl="~/ui/CMS/Admin/Categories.aspx" />
</virtualPathMappings>
  • Add a new location element in web.config for our new virtual path. Here I’m allowing users in the CategoryAdmins and Administrators roles access whilst denying all other users.
<location path="ui/CMS/categoryadmin">
   <system.web>
      <authorization>
         <allow roles="CategoryAdmins, Administrators">
         <deny users="*">
      </authorization>
   </system.web>
</location>
  • Create Action Window plugin – now that we’ve opened up access to the category admin page, we need to define a position for a CategoryAdmin user to access this page from the EPiServer edit interface. I’ve chosen to create an Action window plugin, which is achieved by marking your page class with a GuiPlugin attribute. Don’t forget also to lock down access to this page with a location security configuration.

There is a small choice/compromise here to make about the user experience. You can either use a Server.Transfer call to transfer the Plugin page directly to your virtual url. However you will see some anomalies from the EPiServerUI:SystemPrefix control which provides the page title for most pages in admin mode (this control lives in the EPiServerUI.Master page). The SystemPrefix controls creates the page title from the current url which means that as you’ve used Server.Transfer (which preserves the original request url) you will see a heading of ‘Action Window’.

If you can live with this you’ll get a more straight forward user experience. However I’ve decided that having the correct title is important, so I’ve just provided a simple anchor tag with the Plugin page’s markup which allows a click through to the Category page.

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CategoryAdminPlugin.ascx.cs" Inherits="EPiServer.CategoryAdminPlugin" %>

<h2>Category Admin</h2>
<p>Users in the CategoryAdmin role can access this page.</p>
<asp:HyperLink runat="server" NavigateUrl="~/ui/CMS/CategoryAdmin/Categories.aspx" Text="Edit Categories" />
using System;
using EPiServer.PlugIn;

namespace EPiServer.Plugins
{
   [GuiPlugIn(DisplayName = "Edit Categories",
   Description = "Allow CategoryAdmins to access 'Edit Categories page",
   Url = "~/Plugins/CategoryAdminPlugin.ascx",
   Area = PlugInArea.ActionWindow)]
   public partial class CategoryAdminPlugin : System.Web.UI.UserControl
   {
      protected void Page_Load(object sender, EventArgs e)
      {

      }
   }
}
  • Add new language elements – all quite straight forward so far, but there is one final hurdle to overcome. The categories.aspx page uses the EPiServer LanguageManager to provide the correct language translation for much of the copy on the page. The LanguageManager calculates the Xpath to the specified language element using the current page’s url (*only if the path is within the EPiServer Ui). As our path is virtual, these XPath’s don’t exist, so we must add them to the ~/lang xml files.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<languages>
   <language name="English" id="en">
      <categoryadmin>
         <categories>
            <heading>Categories</heading>
            ... removed for brevity
         </categories>
      </categoryadmin>
   </language>
</languages>
  • The proof! This is a relatively simple technique that allows you to add a small amount of flexibility into the EPiServer edit/admin interface.

Written by mark

August 12th, 2010 at 1:11 pm

Posted in ASP.NET,C#,EPiServer

Removing the empty option from DynamicList properties

without comments

Today seems to be one of those days where you pick up really simple bits of information that you’re surprised you never knew before (see Erik’s post about sending mail in a development environment for example)……

My little snippet comes from a question posted in the EPiServer forums that I responded to; about setting default values on EPiServer DynamicList properties. I’d always wondered how to remove the blank option that’s added by default to the edit mode DropDownList, though never enough to put some code together to actually get rid of it 😉

This morning though, I did just that, and it turned out to be very straightforward as the EPiServer development team had already provided an extensibility point for exactly that scenario.

All that’s needed is a new Property and PropertyControl class that overrides the existing PropertyAppSettings. This class defines a property called AutoGenerateEmptyValue. Override this property to return false to remove the empty value.

using System;
using EPiServer.Core;
using EPiServer.PlugIn;
using EPiServer.SpecializedProperties;
using EPiServer.Web.PropertyControls;

namespace MySite.CustomProperties
{
   [Serializable]
   [PageDefinitionTypePlugIn(DisplayName = "Dynamic list (one option) with no empty value", Description = "Works as the out-of-the-box Dynamic list property but displays no empty option")]
   public class PropertyAppSettingsNoEmptyValue : PropertyAppSettings
   {
      public override IPropertyControl CreatePropertyControl()
      {
         return new PropertyAppSettingsNoEmptyValueControl();
      }
   }

   public class PropertyAppSettingsNoEmptyValueControl : PropertyAppSettingsControl
   {
      protected override bool AutoGenerateEmptyValue { get { return false; } }
   }
}

Written by mark

August 2nd, 2010 at 4:44 pm

Posted in ASP.NET,C#,EPiServer