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