Enabling/attaching and disabling/detaching content providers from Episerver edit UI
How and why you should register content providers from the UI.
Published 15th of december 2018
Episerver > 8
Content Providers in Episerver is a way of publishing external data as pages/blocks etc… but also a way of publishing content in several places on your web/sites. Due to the lack of publishing in several containers/parents, this is a way of cloning data and keeping friendly urls. For example list news or job posts in a multisite environment.
More about coding a provider: https://devblog.gosso.se/2016/09/contentprovider-example-for-episerver-former-pageprovider/
Registering a provider in webconfig / episerver looks like this
<episerver> <contentProvider> <providers> <add entryPoint="66" name="ClonedNews" sourceid="20" categoryid="16" type="Gosso.EPiServer.ContentProviders.ClonedByCategoryContentProvider, GOSSO.EPiServer" /> </providers> </contentProvider> </episerver>
However, this is kind of static, and the downside is that that entrypoint nod/page is disabled for edit.

And sometimes you need to change settings on that page so a better approach would be NOT to register the content provider thru the web.config.
Best practice registering a content provider
First of all, i’ve made a base class for all my startpages (multi site or single site scenario)
using EPiServer.Core;
using System.ComponentModel.DataAnnotations;
namespace Gosso.Mvc.Models.Pages
{
public abstract class JobProviderBasePage : BaseStartPage
{
[Display(
Name = "Activate cloning of job posts on this site",
Description = "",
GroupName = "Job",
Order = 1
)]
public virtual bool EnableProvider { get; set; }
[Display(
Name = "Reload the provider",
Description = "If you want to reload the provider, click here.",
GroupName = "Job",
Order = 2
)]
public virtual bool ReloadProvider { get; set; }
[Display(
Name = "Get from this page (source)",
Description = "",
GroupName = "Job",
Order = 20
)]
public virtual PageReference JobSource { get; set; }
[Display(
Name = "Clone to this page (target)",
Description = "",
GroupName = "Job",
Order = 30
)]
public virtual PageReference JobEntryPoint { get; set; }
[Display(
Name = "Some other input to provider",
Description = "anything you need to your provider",
GroupName = "Job",
Order = 40
)]
public virtual string JobCategories { get; set; }
}
}
Use a onPublishing event to handle changes “ReloadProvider”
//in an [InitializableModule]
IContentEvents events = ServiceLocator.Current.GetInstance<IContentEvents>();
events.PublishingContent += PublishingContent;
private void PublishingContent(object sender, ContentEventArgs e)
{
if (!(e.Content is PageData))
return;
if (ContentReference.IsNullOrEmpty(e.ContentLink))
return; //new page
if (e.Content is JobProviderBasePage)
{
JobProviderBasePage oldPage = ProviderHelper.GetLastVersion(e.ContentLink.ToPageReference(), (e.Content as ILocalizable).MasterLanguage.TwoLetterISOLanguageName) as JobProviderBasePage;
if (oldPage != null && oldPage.ReloadProvider != (e.Content as JobProviderBasePage).ReloadProvider)
{
(e.Content as JobProviderBasePage).ReloadProvider = false;
ProviderHelper.ReloadProvider((e.Content as JobProviderBasePage));
}
}
}
Then i have a helper class to manage the load/reload/remove providers
using EPiServer;
using EPiServer.Configuration;
using EPiServer.Construction;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.ServiceLocation;
using EPiServer.Web;
using Kriminalvarden.Mvc.Models.Pages;
using log4net;
using System;
using System.Collections.Specialized;
using System.Linq;
namespace Gosso.Mvc.Business.ContentProviders
{
/// <summary>
/// Helpers for the content providers
/// </summary>
public static class ProviderHelper
{
#region Static Fields
/// <summary>
/// Initializes the <see cref="LogManager">LogManager</see>
/// class.
/// </summary>
private static readonly ILog Logger = LogManager.GetLogger(typeof(ProviderHelper));
#endregion
#region Public Methods and Operators
public static bool AddJobProvider(string name, JobProviderBasePage jobsettings)
{
if (jobsettings != null && jobsettings.JobCategories != null
&& jobsettings.JobEntryPoint != null
&& jobsettings.JobSource != null)
{
var provider = new JobPageClonedContentProvider(
ServiceLocator.Current.GetInstance<IdentityMappingService>(),
ServiceLocator.Current.GetInstance<IContentTypeRepository>(),
ServiceLocator.Current.GetInstance<IContentFactory>(),
ServiceLocator.Current.GetInstance<IUrlSegmentGenerator>(),
ServiceLocator.Current.GetInstance<IContentCacheKeyCreator>(),
ServiceLocator.Current.GetInstance<IContentRepository>());
// add configuration settings for entry point and capabilites
var providerValues = new NameValueCollection();
providerValues.Add(ContentProviderElement.EntryPointString,
jobsettings.JobEntryPoint.ToString());
providerValues.Add("sourceid", jobsettings.JobSource.ToString());
providerValues.Add("categoryids", jobsettings.JobCategories);
try
{
provider.Initialize(name, providerValues);
var providerManager = ServiceLocator.Current.GetInstance<IContentProviderManager>();
providerManager.ProviderMap.AddProvider(provider);
return true;
}
catch
{
return false;
}
}
return false;
}
/// <summary>
/// Deletes the provider.
/// </summary>
/// <param name="providerName">Name of the provider.</param>
/// <returns> <c>true</c> if [the provider was removed]; otherwise, <c>false</c>.</returns>
/// <exception cref="System.InvalidOperationException">
/// Provider setting not found.
/// or
/// </exception>
public static bool DeleteProvider(string providerName)
{
IContentProviderManager providerManager = ServiceLocator.Current.GetInstance<IContentProviderManager>();
ContentProvider pageProvider = providerManager.ProviderMap.GetProvider(providerName);
try
{
if (pageProvider != null)
{
providerManager.ProviderMap.RemoveProvider(providerName);
}
CacheManager.Clear();
}
catch (Exception exception)
{
Logger.Error(exception.Message, exception);
throw new InvalidOperationException(exception.Message);
}
return true;
}
#endregion
public static bool ReloadProvider(JobProviderBasePage jobProviderBasePage)
{
if (jobProviderBasePage.EnableProvider)
{
if (DeleteProvider("jobprovider-" + SiteDefinition.Current.Name))
{
return AddJobProvider("jobprovider-" + SiteDefinition.Current.Name, jobProviderBasePage);
}
else
return false;
}
else
{
return DeleteProvider("jobprovider-" + SiteDefinition.Current.Name);
}
}
public static IContent GetLastVersion(PageReference reference, string lang)
{
var versionRepository = ServiceLocator.Current.GetInstance<IContentVersionRepository>();
var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
var versions = versionRepository.List(reference);
var lastVersion = versions
.OrderBy(v => v.Saved)
.Take(versions.Count() - 1)
.OrderByDescending(v => v.Saved)
.FirstOrDefault(version => version.LanguageBranch == lang);
if (lastVersion == null)
{
//var msg = string.Format("Unable to find last version for ContentReference '{0}'.", reference.ID);
//throw new Exception(msg);
return null;
}
return contentRepository.Get<IContent>(lastVersion.ContentLink, LanguageSelector.AutoDetect(true));
}
public static bool AddJobProviderSite1(string name)
{
if (ServiceLocator.Current.GetInstance<IContentLoader>().TryGet(ContentReference.StartPage, out StartPage startpage))
{
if (ServiceLocator.Current.GetInstance<IContentLoader>()
.TryGet(startpage.Site1Start, out JobProviderBasePage jobsettings))
{
if (jobsettings.EnableProvider)
return AddJobProvider(name, jobsettings);
}
}
return false;
}
public static bool AddJobProviderSite2(string name)
{
if (ServiceLocator.Current.GetInstance<IContentLoader>().TryGet(ContentReference.StartPage, out StartPage startpage))
{
if (ServiceLocator.Current.GetInstance<IContentLoader>()
.TryGet(startpage.Site2Start, out JobProviderBasePage jobsettings))
{
if (jobsettings.EnableProvider)
return AddJobProvider(name, jobsettings);
}
}
return false;
}
}
}
Last, Register from code OnInit
//in an [InitializableModule]
//programmatically registering a content provider
ProviderHelper.AddJobProviderSite2("jobprovider-sitename");
SEO terms
- Attaching ContentProviders programmatically
- Reset content providers runtime
- programmatically add content provider
About the author
Luc Gosso
– Independent Senior Web Developer
working with Azure and Episerver
Twitter: @LucGosso
LinkedIn: linkedin.com/in/luc-gosso/
Github: github.com/lucgosso