To view the complete list of changes, see the release notes feed.
Binary breaking changes do not necessarily require code changes but rather just a recompilation of the project. Optimizely Content Management System (CMS 12) breaking changes to method signatures or to the behavior of methods, compared to the documented API in CMS 11, are described in this topic.
Version 12 targets ASP.NET Core so breaking changes between ASP.NET and .NET Framework 4.x to ASP.NET Core apply to CMS projects also. For example, this includes ending support for writing templates that use WebForms or having WebForms views in MVC.
A breaking change may cause a component to fail. When a breaking change is made to a signature of a method, class, or interface, the former signature is often kept intact but set as obsolete and may cause a warning message in Visual Studio. To delay fixing the warning messages, you can disable Treat Warnings as Errors [right-click on your project > Properties > Build > set Treat Warnings as Errors to Specific warnings or None].
Classes that expose constructors that take dependencies are normally deleted without an obsolete warning in major releases because the compiler provides information about what you need to change. Keeping those classes makes dependency injection complex because, over time, there would be multiple constructors to choose from that might overlap.
In each major version, obsolete methods are removed permanently to keep the API clean and usable. If you could postpone fixing warning messages, you should make sure warning messages are fixed before upgrading to a major version. For CMS 12.0, many methods that were made obsolete in prior versions are now deleted.
You should use the Upgrade Assistant to migrate from a CMS 11 project to CMS 12 because the tool manages most of the package updating.
Some packages are ASP.NET-specific and are available only for CMS 11. The following list of packages is no longer applicable in CMS 12. Corresponding packages are shown in the CMS 12 package column:
|CMS 11 package
|CMS 12 package
|Umbrella package for CMS. Includes packages used for rendering and CMS UI.
|EPiServer.Cms.AspNet contained general web-related CMS features, including routing, WebForms, MVC and so on. This was split into several different packages. EPiServer.Cms.AspNetCore.HtmlHelpers is the "top" package of this, meaning referencing that gives indirect dependency to the other packages.
|Some general web-related implementations, such as VirtualPathProviders, FileProviders.
|Dependency injection implementation. Not applicable in CMS 12 because ASP.NET Core includes a DI framework.
|Logging implementation for log4net. Not applicable in CMS 12 since custom logging is configured directly towards .NET Core APIs.
You can use the optional package
EPiServer.CMS.AspNetCore.Migration for projects that are migrating from CMS 11 to CMS 12. The package contains some old APIs, such as
DataFactory and support for XML-based .config files. If you use an existing
web.config, you should rename the config file to
app.config so that
ConfigurationManager will load it.
In ASP.NET Core, a dependency injection (DI) framework is built into the platform. In prior versions, Optimizely CMS had its own DI hosting framework that supported different concrete DI systems. In version 12, there is no longer a DI hosting framework within CMS; instead, the DI system is a layer on top of the built-in DI framework in ASP.NET Core. See Dependency injection.
In prior versions of CMS, there was a DI hosting framework within CMS and then concrete packages like
EPiServer.ServiceLocation.StructureMap for specific DI implementations. CMS is configured to use the default DI implementation in ASP.NET Core. The required code in
Program.cs to connect the DI framework in ASP.NET Core with CMS is the call to the extension method
ConfigureCmsDefault(), as in the following example:
public static IHostBuilder CreateHostBuilder(string args) =>
We recommend using the built-in DI framework described above, which is the only framework we do testing on. To use a different DI framework than the built-in, the call to
ConfigureCmsDefault() should be replaced with a call to
UseServiceProviderFactory passing in an instance of
ServiceLocatorProviderFactoryFacade and then passing in the actual implementation to use. Below is an example of how to configure the application to use Autofac (given that there is a reference to the Autofac NuGet package):
public static IHostBuilder CreateHostBuilder(string args) =>
Unlike DI frameworks like StructureMap, which supports the auto-resolving of concrete types, the built-in DI framework requires you to register used services in the IOC container explicitly.
In prior versions of CMS, you could scope a service as 'HttpContext' or 'Hybrid'. In version 12, the lifetimes are the same as in .NET Core, that is, Transient, Scoped, or Singleton.
Previously, when there was no built-in DI framework in ASP.NET, using the static property
common.Current to access the DI container in WebForms or views (for example).
In CMS 12, when there is a built-in DI framework that is accessible, for example, through
HttpContext, there are not many places where you need to use
If, however, you use
ServiceLocator.Current outside a web request, you have to create custom scopes, you should create the scopes using extension method
CreateServiceLocatorScope instead of the extension method
CreateScope within .NET Core. This makes the static accessor
ServiceLocator.Current aware of the custom-created scopes. CMS automatically creates a scope for each scheduled job execution.
In ASP.NET Core, a logging framework is built into the platform. In prior versions, Optimizely CMS had its logging framework that supported different concrete logging systems, such as
In version 12, there is no longer a logging hosting framework within CMS; instead, the logging system in CMS (
EPiServer.Logging namespace) is a layer on top of the built-in logging framework in ASP.NET Core. To configure logging for CMS, you configure logging in the same way as for a plain ASP.NET Core site, see Logging in .NET Core. To do custom logging, you should take a dependency to an
Micrsoft.Extensions.Logging namespace. For projects that are upgraded that today use APIs in
EPiServer.Logging, you can continue to do so because that API acts as a façade over the logging APIs in .NET Core.
In prior versions of CMS, the routing was based on the API defined in System.Web.Routing. This API is no longer available in ASP.NET Core, so the routing system in CMS was rewritten to work with endpoint routing in ASP.NET Core. See Routing.
In CMS 11, routing was executed after the user was authenticated. In an ASP.NET Core application,
.AddRouting() is typically called before
.AddAuthentication(). This means that the user is not authenticated during routing; instead, authorization is performed after authentication, and the user is evaluated against the
episerver:read policy at this stage. Therefore, extensions like partial routers and/or events to route events, should not perform access checks since the user is not authenticated at that stage.
In CMS 11 was the request language (
IContentLanguageAccessor.Language) set early during routing when processing host and language segment. This meant that partial routers could use them (for example, implicitly through
IContentLoader). In CMS 12, the request language is not set until routing has been completed. This means that partial routers should not rely on them being set but should instead explicitly pass in language when loading content through
IContentLoader. The routed language is available in a routing context passed into partial routers or routing event handlers.
Previously, there were events exposed by
EPiServer.Web.Routing.IContentRouteEvents. This interface was made obsolete and replaced by
IPartialRouter changed slightly, and implementations should now be registered in DI container as
IPartialRouter, rather than the previous way to register a partial router, which was through the extension method
Previously, you could define content routing with custom parameters using extension methods starting with
In CMS 12, to register custom parameter routing for content routes, you can use the method
IContentEndpointRouteBuilder that is returned when extension method
MapContent is called on
Previously, you could use
RouteCollection extension methods
MapEnterpriseRoutes to register content routes for custom content roots (the content item where the routing starts from). You can also register optional static segments for the routes.
This was replaced by the interface
EPiServer.Core.Routing.Pipeline.IContentRouteRegister you can implement and register in a DI container to define a custom content root registration.
Previously, you could get content URLs using MVC extension methods like
Html.BeginForm. This no longer works. Instead, replace them with calls to
In previous (ASP.NET-based) versions, you configured through
In CMS 12, you can configure data through option classes, programmatically through code, or populated from a configuration file like
appSettings.json, or through environment variables. See configuration in .NET Core.
You can use the
EPiServer.CMS.AspNetCore.Migration package for projects that are upgrading to CMS 12. That project enables populating options from "old" XML-based .config files. You should also rename the current
web.config file to
This project handles only Optimizely-specific config sections like <episerver>, <episerver.framework>, <episerver.shell> and so on.
See Configuration to configure the CMS.
In DXP, Multiple Active Record Sets were disabled in the connection string.
Previously when selecting which templates to use in On-page editing, the template selector first searched for a template with the tag Edit, then a template without a tag, and finally a template with the tag Preview. This was changed so that on-page edit it only searches for a template with the tag Edit and then the template with no tag (that is template with the tag Preview is not searched for during on-page edit).
So if you have a template just tagged with Preview that was used for preview and on-page edit, you must add the tag 'Edit' to the template registration to register the template for on-page edit.
Previously, you could use
GuiPlugInAttribute to extend admin mode with UI plugins based on the previous WebForms admin mode. The new admin mode does not support
Instead, you should extend admin mode to register a menu provider.
Previously, you could register
PagePlugInAttribute to extend WebForms requests. However, WebForms is no longer supported, and neither is
Instead, you should extend requests to register action filters and/or middleware components.
The CMS 11 dashboard was not ported to CMS12. An alternative to show custom user interfaces in the CMS UI is to extend the menu system as described in Extend the navigation Optimizely CMS 11.21 and higher topic.
The Report section in CMS UI was restored to CMS 12 . The Reports tab, which was available in CMS 11, is now available in CMS 12 (starting with
EPiServer.CMS.UI 12.12.0) including reports such as Not Published Pages, Published Pages, Changed Pages, Expired Pages, Simple Addresses and Link Status.
In ASP.NET, you could register virtual path providers to map virtual paths to files. CMS contained some virtual path provider implementations such as
VirtualPathNonUnifiedProvider. A similar concept in .NET Core is
IFileProviders and CMS registers a composite file provider that delegates requests to registered file providers. The corresponding file provider implementation to
MappingPhysicalFileProvider. To add custom
fileproviders, register them towards
See File Providers to work with file providers within CMS.
In ASP.NET, you can restrict access to certain virtual paths by defining an authorization element in
web.config for a specific path and then define which users or roles can access that path. In a default CMS 11 installation, virtual path
/EPiServer is restricted to roles WebEditors, WebAdmins, and Administrators. In ASP.NET Core,
web.config is gone so you cannot restrict access to virtual paths similarly.
In CMS 12, shell modules are registered with a policy that specifies who can access resources from the module. A shell module's manifest defines which policy applies to a module. If you specify no policy, then
CmsPolicyNames.DefaultShellModule is registered by default. You can configure the members of the default policies using
Membership and Role providers are not supported in ASP.NET Core.
System.Text.Threading.CurrentPrincipal assigned from
HttpContext.Current.User, but this is no longer the case in ASP.NET Core, as mentioned in Migrate from ClaimsPrincipal.Current. One effect of this is that in CMS 11 you could use
PrincipalInfo.CurrentPrincipal and get the user who started a scheduled job when a job was started manually. This is no longer possible in CMS 12.
The profile provider system that exists in ASP.NET is not available in ASP.NET Core. If you use ASP.NET identity, you can manage additional user data there.
In previous versions, you could not configure the CMS to run as a virtual application in IIS. Virtual application is an IIS-specific feature and CMS 12 is designed to be cross-platform, so it does not require IIS. Running CMS as a virtual application is no longer supported.
In previous versions, you could initialization modules to implement interface
IInitializableHttpModule and get access to the
HttpApplication, which could setup event handlers for ASP.NET events. The HTTP pipeline is different in ASP.NET Core than in ASP.NET, so there are no longer similar events; the interface
IInitializableHttpModule no longer exists.
In ASP.NET Core, you should register a middleware component to get access to each request.
The remote event provider replicates information between instances running the application, to synchronize cache invalidations across instances in a load-balanced environment. In CMS 11, a WCF-based event provider supported communication over TCP or UDP. WCF is not supported in .NET Core, and that provider was not converted, so no event provider communicates over TCP or UDP included in CMS. We recommend using the provider based on Azure Service Bus.
In CMS 11, a WCF-based search service was based on a local Lucene index.
WCF is not supported in .NET Core, and that search service was not converted, so there is no local search service that you can install.
In CMS 12, use Optimizely Search & Navigation for search.
In ASP.NET MVC, you could have a partial controller that was called as part of the execution of another controller. For example, you could use the
PartialContentController<TContent> classes as base controllers for such a "partial" controller, but they were converted to view components in CMS 12.
In CMS 12, you should change the base class to
Mirroring is unavailable in CMS 12 because it was based on WCF, which is not supported in .NET Core.
XForms is not available in CMS 12. You should use Optimizely Forms instead.
The user interface to edit dynamic properties was based on WebForms and was not ported, so you cannot edit dynamic properties through the UI. The API support for dynamic properties is obsoleted and disabled by default but can be enabled via options as a temporary solution when upgrading a site. API support will be removed in a future version.
HttpHandlers are no longer supported in ASP.NET Core and, so
BlobHttpHandler classes are no longer available.
UrlRewriteProvider generated friendly URLs for WebForms. CMS 12 does not support WebForms, so you cannot use
UrlRewriteProviders. See Routing.
Datetime handling of audience criteria
EventModel that has changed from
The time in the database should be converted to UTC. See Store UTC date and time in the database (Legacy).
Updated 28 days ago