How to create a custom login page in EPiServer MVC with OWIN


It's very easy to create a custom login page using the new AspNetIdentityPackage however the biggest problem I encountered was the lack of support for RedirectUrl, user would always be redirected back to the start page.

However, after a bit of digging I made it to work. Please take a look: Custom Login Page

The diff to the current Alloy MVC is here: Custom Login Page Diff

You can just clone my repository and follow the Readme to see it in action.

The problem was to override our default behavior of handling ReturnUrl which we always read from QueryString, however in case of a custom login screen that value is passed in form data. It was easy to do by overriding the default UISignInManager with a custom implementation with an overridden SignIn method that would skip the redirect and let your login controller to do the work.

public class CustomApplicationUISignInManager<T> : ApplicationUISignInManager<T>
  where T : IdentityUser, IUIUser, new()
  private readonly ServiceAccessor<ApplicationSignInManager<T>> _signInManager;

  public CustomApplicationUISignInManager(ServiceAccessor<ApplicationSignInManager<T>> signInManager)
    : base(signInManager)
    _signInManager = signInManager;

  public override bool SignIn(string providerName, string userName, string password)
    return _signInManager().SignIn(userName, password, string.Empty);

and registration in Startup.cs

// Add CMS integration for ASP.NET Identity
app.CreatePerOwinContext<UISignInManager>((options, context) =>
    new CustomApplicationUISignInManager<ApplicationUser>(context




How to run EPiServer from console

Have you ever added admin mode plugins with a single button to run 1-time jobs like import / cleanup / data migration?

Or have you ever added a scheduled job just to run a long running task and see the progress.

Well...I did that plenty of times.

Wouldn't it be easier to just run those kind of 1-time jobs from the console and just forget about stuff like sessions, timeouts, web.config etc.?

Of course, I'm not saying that scheduled jobs or plugins are a bad thing, sometimes there is just no other way. But in most cases, it's easier to use a good old terminal.

A while ago, while visiting the HQ in Stockholm, me & Greg spent a few hours to create a simple tool that would let you do just that.

The idea is simple, you run a console app with a set of parameters:

  • Application Path ( -p ) - path to the folder that contains your webapplication
  • Task Assembly ( -a ) - path to the assembly that contains your custom tasks
  • Tasks ( -t ) - an ordered list of tasks from the Task Assembly

Here it is in action:

As you can see it's easy to use it. You can also report progress back from your tasks if necessary.

The tasks are simple objects with an Execute method. We use duck typing and would only execute those that contain that method.

A basic example of a task is as following:

public class SampleTask1
    private readonly IContentRepository _contentRepository;

    public event EventHandler<ProgressChangedEventArgs> Progress;

    public SampleTask1(IContentRepository contentRepository)
        _contentRepository = contentRepository;

    public void Execute()
        var totalPages = 20;

        for (int i = 1; i < totalPages; i++)
            var articlePage = _contentRepository.GetDefault<ArticlePage>(ContentReference.StartPage);
            articlePage.Name = "First sample page " + i;
            _contentRepository.Save(articlePage, SaveAction.Publish, AccessLevel.NoAccess);
            Progress?.Invoke(this, new ProgressChangedEventArgs((100 * i)/ totalPages, null));

        Progress?.Invoke(this, new ProgressChangedEventArgs(100, null));

It can either be a part of your web application project or it can also be placed in a separate project if you for example don't need to use the model classes.

The code that finds task classes is very simple:

public class TasksLoader
    private const string ExecuteMethodName = "Execute";
    private const string ProgressEventName = "Progress";
    private readonly IServiceLocator _serviceLocator;

    public TasksLoader(IServiceLocator serviceLocator)
        _serviceLocator = serviceLocator;

    public IEnumerable<EpiTask> Load(Assembly assembly, IEnumerable<string> tasks)
        var types = assembly.ExportedTypes.Where(t => tasks.Contains(t.Name, StringComparer.InvariantCultureIgnoreCase)).ToList();
        if (types.Count != tasks.Count())
            var missingTaskClasses = tasks.Except(types.Select(t => t.Name));
            throw new ArgumentException($"Invalid task class {string.Join(",", missingTaskClasses)} provided.");
        foreach (var task in tasks)
            var type = types.First(t => t.Name == task);
            var executeMethod = type.GetMethod(ExecuteMethodName, BindingFlags.Public | BindingFlags.Instance);
            if (executeMethod == null)
                throw new ArgumentException($"The task {type} is missing the {ExecuteMethodName} method.");

            yield return new EpiTask
                Type = type,
                Instance = _serviceLocator.GetInstance(type),
                ExecuteMethod = executeMethod,
                ProgressEvent = type.GetEvent(ProgressEventName)

Each of EpiTask instances is then passed to the TaskRunner and executed:

public class TaskRunner
    private readonly IServiceLocator _serviceLocator;
    private ProgressBar _pbar;

    public int? tick;

    public TaskRunner(ProgressBar pBar)
        this._pbar = pBar;

    public void Run(EpiTask epiTask)
        if (epiTask.ProgressEvent != null)
            var showProgressMethod = this.GetType()
                .GetMethod("ShowProgress", BindingFlags.Instance | BindingFlags.Public);
            var tDelegate = epiTask.ProgressEvent.EventHandlerType;
            var handler = Delegate.CreateDelegate(tDelegate, this, showProgressMethod);
            epiTask.ProgressEvent.AddEventHandler(epiTask.Instance, handler);
        epiTask.ExecuteMethod.Invoke(epiTask.Instance, null);

    public void ShowProgress(object sender, ProgressChangedEventArgs eventArgs)
        if (!tick.HasValue)
            tick = (int)(100 / (eventArgs.ProgressPercentage));


The only tricky part was to initialize the framework. We don't have the web.config in the console app so we have to first point it to the site's web.config and then force it to load the correct episerver.framework section in order to initialize the base framework modules.

Console.WriteLine("Initializing EPiServer environment");

var fileMap = new ExeConfigurationFileMap
    ExeConfigFilename = Path.Combine(commandLineParams.AppPath, "web.config")
var config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var section = config.GetSection("episerver.framework") as EPiServerFrameworkSection;
ConfigurationSource.Instance = new FileConfigurationSource(config);

var assembly = Assembly.LoadFrom(commandLineParams.TaskAssembly);
var assemblyName = AssemblyName.GetAssemblyName(commandLineParams.TaskAssembly);

If you use localdb then there's also a little trick that you need to do because the 'DataDirectory' variable is resolved by runtime and we are running our app from the console so we have a problem ;)

Fortunately it's also easy to fix using an instance of SqlConnectionStringBuilder and replacing the connectionString with a real path (without |DataDirectory| variable).

var connectionString = config.ConnectionStrings.ConnectionStrings["EPiServerDB"];
var builder = new SqlConnectionStringBuilder(connectionString.ConnectionString);

if (!string.IsNullOrWhiteSpace(builder.AttachDBFilename))
    builder.AttachDBFilename = builder.AttachDBFilename.Replace("|DataDirectory|",
        Path.Combine(commandLineParams.AppPath, "App_Data") + "\\");
connectionString.ConnectionString = builder.ConnectionString;

The whole code is available on

Customizing TinyMCE Styles Dropdown programatically

I have recently received a question from one of the developers on how to provide a different set of TinyMCE Styles in a multi site environment. 

The expected result was to be able to change both the applied styles in the html editor and the dropdown that is used to choose a particular style.

There is a great post by Arve Systad about Setting editor stylesheets programmatically that is a great starting point for our problem.

We would create an EditorDescriptor where we would place the logic that returns different stylesheets per site.

using System;
using System.Collections.Generic;
using System.Linq;
using EPiServer.Cms.Shell.UI.ObjectEditing.EditorDescriptors;
using EPiServer.Core;
using EPiServer.Editor.TinyMCE;
using EPiServer.Shell.ObjectEditing;
using EPiServer.Shell.ObjectEditing.EditorDescriptors;
using EPiServer.Web;
using EPiServer.Web.Hosting;

namespace AlloyTemplates.Business.EditorDescriptors
    [EditorDescriptorRegistration(TargetType = typeof(XhtmlString), EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)]
    public class MyEditorDescriptor : XhtmlStringEditorDescriptor
        public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
            base.ModifyMetadata(metadata, attributes);

            var tinyMceSettings = metadata.EditorConfiguration.FirstOrDefault(x => x.Key == "settings");
            var dictionary = tinyMceSettings.Value as Dictionary<string, object>;
            if (dictionary == null) return;

            var formatter = new TinyMCEStyleFormatter();

            var staticCssEditorCss = SiteDefinition.Current.Name.Equals("Foo") ? "/Static/css/editor.css" : "/Static/css/editor2.css";

            dictionary["content_css"] = staticCssEditorCss;
            using (var stream = GenericHostingEnvironment.VirtualPathProvider.GetFile(staticCssEditorCss).Open())
                var styleFormats = formatter.CreateStyleFormats(stream);
                dictionary["style_formats"] = styleFormats;

content_css property is responsible for styling the editor whereas style_formats is responsible for populating the styles dropdown.

Let's imagine we have two separate stylesheets:

  • editor1 - which should be used in the "Foo" site
h2 {EditMenuName:Header 2;color:red;}
h3 {EditMenuName:Header 3;}

h2 {
  • editor2 - which should be used in all other sites
h2 {EditMenuName:Alternative Header 2;color:blue;}
h3 {EditMenuName:Alternative Header 3;}
h4 {EditMenuName:Alternative Header 4;}

h2 {

The end result would look as following:



Annotation rewriter from CMS6 to CMS7

I was given a task to rewrite the annotations in our codebase - we use PageTypeBuilder so each of our page types is defined as following:

[PageType("a653d556-7b52-46e9-87be-83a2a351dc88", AvailableInEditMode = true, AvailablePageTypes = new[] { typeof(BannerPage) })]
public class ArticlePage: PageData {...}

EPiServer upgrade manual says that you should:

  1. Run the upgrade through Deployment Center
  2. Fix compilation errors
  3. Run the solution
However the problem in our case was that CMS is only a part of our enterprise solution and we cannot afford to stop developing new features - most of the team were still actively adding new features to the same codebase.
In order to avoid merging horror I decided to try to stay in trunk for as long as I can and to postpone branching to the very last moment.
My idea was to utilize precompiler directives and conditionally compile different annotations for different CMS versions.
As an example please find the following definition of a page type:
[EPiServer.DataAnnotations.ContentType( GUID = "16496e84-3756-44f8-a0a2-a57fc40b9baa")]
[EPiServer.DataAnnotations.AvailableContentTypes(Include = new[] { typeof(CommentPage), typeof(ModuleContainer), typeof(Module) } )]
,Filename = "~/Templates/Pages/Common/News/NewsPageTemplate.aspx"
,AvailablePageTypes = new [] { typeof(CommentPage), typeof(ModuleContainer), typeof(Module) }
public class ArticlePage {...}

I had a vision to write a tool that automatically browses through our codebase and transpiles page type builder definitions into those kind of conditional definitions.
I decided to implement it using Roslyn and its powerful implementation of the visitor pattern.
However I found it quite time consuming (I will share some more details in a future post).

Because of the complexity I decided to try with good-old regex ;)

First off we have to scan the source code for page type definitions:


As you see I defined several named groups to extract all important properties out of the definitions. Next, we have to Regex.Replace

The replacement string is as follows:

[EPiServer.DataAnnotations.ContentType(DisplayName = "${Name}", GUID = "${GUID}", AvailableInEditMode = ${AvailableInEditMode}, Order = ${SortOrder})]
[EPiServer.DataAnnotations.AvailablePageTypes(Include = new[] { ${AvailablePageTypes} }, Exclude = new []{${ExcludedPageTypes}} )]

Analogically you can do the same with properties:


And the replacement is as follows:

 Name = "${EditCaption}"
 , Description = "${HelpText}"
 , Order = ${SortOrder}
 , GroupName = "${Tab}"

What you have to do is simply enumerate through all project files and try to match/replace

var directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var pageModelsPath = Path.Combine(directory, "PageModels");
var enumerable = FilesHelper.GetFiles(pageModelsPath).ToList();
foreach (var file in enumerable)
 var code = File.ReadAllText(file);
 var pageRegex = new Regex(RegexExpressions.PageTypeExpression);
 var propertyRegex = new Regex(RegexExpressions.PageTypePropertyExpression);
 if (pageRegex.Match(code).Success == false && propertyRegex.Match(code).Success == false)
 code = pageRegex.Replace(code, RegexExpressions.PageTypeReplacementExpression);
 code = propertyRegex.Replace(code, RegexExpressions.PageTypePropertyReplacementExpression);

Unfortunately this approach generates a lot of noise; regex does not support conditionals so it's not possible to say: 'IF namedGroup[ExcludePageTypes] is not null then ...'. You can simply provide only 1 replacement string.

Thus, I had to do a little cleanup afterwards.

code = new Regex("\\w+\\s*=\\s*\"\"\\s*,?").Replace(code, string.Empty);
code = new Regex("\\[[\\w\\.]+\\(\\)\\]").Replace(code, string.Empty);
code = new Regex("\\[.+\\(\\)\\)\\]").Replace(code, string.Empty);
code = new Regex("\\w+\\s*=\\s*,").Replace(code, string.Empty);
code = new Regex(",\\s*?\\w+\\s*=\\s*\\)").Replace(code, ")");
code = new Regex(",?\\s*\\w+\\s*=\\s*new\\s*\\[\\]\\s*\\{\\s*\\}").Replace(code, string.Empty);
code = new Regex(",\\s*\\)\\]").Replace(code, ")]");

The end results are very satisfactory. The team is still doing new features and I am able to work in the same branch as them doing CMS7+ related stuff.

The only downside is that I needed to add a separate sln/csproj files (blind copies of existing files) that have EPISERVER_8 conditional compilation symbol set.

Ambiguous match found - thrown from ContentData Metadata Provider

I’m in the middle of a big upgrade from CMS6R2 to 7.19.2 and I faced an interesting problem.

It seemed that EPiServer was not able to match interface literal to a valid type. I decided to dig in to EPiServer core to find out what the problem is:

propertyWithAttributes is then passed to a special method that tries to extract the typename and propertyname.

private static PropertyInfo GetPropertyInfoFromInterface(Type modelType, string propertyWithAttributesName)
 string[] strArray = propertyWithAttributesName.Split(new char[] { '_' });
 if ((strArray.Length == 2) && (modelType.GetInterface(strArray[0], true) != null))

As you can see the interface is not fully qualified (it should be episerver.core.icontent_name) and unfortunately we had an interface IContent in our codebase (used for different purposes) which effectively prevented it from working...
After we changed our internal IContent to a different name, everything started to work.

How to speed up TFS build

If for some reason your TFS build takes up long time to finish, you can easily reduce that time by following a few simple steps:

  • Stop indexing sources
  • Deploy only the files that are necessary to run the application
  • Disable "Analyze test impact"
  • Disable "Associate Changesets and Work Items"

In my case the initial build time took ~130 seconds.

After introducing those simple steps I reduced that time to 70 seconds.

In case you have a big team, that's constantly contributing that really makes a difference! :)

Top 3 reasons why we don't like TFS

If you've ever used TFS you'll know what I'm talking about here...

I cannot image how it's possible that such a company as Microsoft produces such an immature tool.

Really, I'm a big fan of Microsoft but every following version of TFS copies the same little bugs that basically make it almost unusable and very "user unfriendly".

It would take a few hours of research or simply asking the community a few simple questions, something like "what is the most frustrating thing about TFS". I bet that all the answers would be quite similar.

I did that job for Microsoft, here are the most criticized "features" of TFS:

  • You have to be online (every little change you make needs to be synchronized with the server)
  • Everything is read-only (you cannot simply edit the file in another editor, first you have to check it out or explicitly make it writable)
  • Check-in file list shows identical files (even though TFS only cares about file contents it cannot determine whether the file has actually been changed or not, it simply shows all checked-in files)

I think you will all agree that for Microsoft, a company with dozens of brilliant engineers, it should be quite important to meet those community expectations.

By the way...I always wonder if they used TFS to store the whole codebase for Windows, Office etc... :)