Oct 21, 2016
(17 votes)

Introducing changes to reduce our Public API

One of the primary considerations when building a software platform that other developers based their work on is to maintain backwards compatibility. As the platform grows larger and more complex this can become the major restraining factor when trying to sustain a high development pace.

Once you start to use strict semantic versioning it becomes glaringly obvious that no API changes can be done no matter how small the change or how obscure the class is, unless releasing a new major version. And while releasing a new major version might not be as big a deal as it used to be, it does add additional work, not just internally, but also for any maintainers of third party modules trying to keep their modules up to date.

internal, <internal /> or .Internal?

The typical approach to this problem is to keep your public classes to a minimum and only expose classes that are actually useful to interact with for external developers. Limiting the API is currently done primarily by keeping classes or methods internal. And while we might be high-fiving each other at the office every time we can add the internal keyword to a class, it seems like it is making some of you platform users less happy, some more than others.

Another option is to use the API documenation and explicitly call out the classes and methods that are considered internal. And while this method has been used with some success in the past, such in the case of the EPiServer.DataAccess namespace, it can sometimes be hard to keep track of which APIs are public or not if they are spread out.

For quite some time now we have been discussing better ways to manage these API restrictions. But as always, while you discuss, other people do, and this is exactly what Microsoft has done. In their latest .NET Core platform they have introduced the notion of “Internal namespaces”, which is a specific namespace pattern that indicates that you are now dealing with classes that are not a part of the public API. As this was very closely aligned with our own thoughts we have decided to follow suit and use the same approach.

This means that going forward any class located in a namespace named 'Internal' will not be considered a part of our supported public API. These classes can still be used, they are just not covered by the semantic versioning promise and can therefore change between minor releases without prior warning. Any problem that arise from using it will also not be covered by our usual support.

It should however mean that we can expose more classes as public in our assemblies so that they are easier to use if you really, really need to or for any non-production scenarios such as for unit testing.

This does not imply that everything outside these namespaces will be a part of the public API as there will still be classes and methods that are explicitly documented as being for “internal use” but we will try to keep these to a minimal whenever possible.

When should I start to notice these changes?

There are some areas in CMS and other products where you can already find Internal namespaces, but so far the use has been relatively limited.

In our next major release, Episerver CMS 10, which is just around the corner, you will notice that we have moved a lot of the classes from their current location to these Internal namespaces in an attempt to minimize the weight of our legacy backpack. This will include any classes that we do not consider important for typical use cases or implementations of public abstractions.

So when you upgrade a solution, please be careful and make sure that you don’t accidentaly add any Internal namespaces to your using statements as this may cause you some problems in the future.

That should be public!

Should you find a class or interface that you believe should have remained in the public API, please contact us and tell us why you think this should be the case.

Oct 21, 2016


Oct 21, 2016 10:06 AM

Sounds great! Totally agree!

Petter Klang
Petter Klang Oct 21, 2016 10:11 AM

-External highfive-

Dec 13, 2016 05:51 PM

Hi and thanks for the article. 

However it would be nice with a follow-up article on how to solve some errors after upgrading to 10.


Eric Jan 19, 2017 03:55 PM

Hi would it be possible with an example how to solve some of the errors after upgrade? I can see in you own alloy demokit you change your code to use internal like the DynamicContentFactory for instance. 

Dick Scherpenzeel
Dick Scherpenzeel May 29, 2017 01:54 PM

How about ContentDB? This type is not mentioned in the breaking changes / release notes (CMS-3762 / CMS-3755). We use the ContentDB.BeforeSavingProperty event to detect changes made to Dynamic Properties. However after upgrading (from 9) to 10 it's not available anymore. Is there a new way to detect changes made in Dynamic Properties? 

I know in documentation it says 'This member supports the EPiServer infrastructure and is not intended to be used directly from your code.' since version 7 (or maybe even earlier, and I think it was available through PageDB before that). However it was there and we need(ed) it so we used it...

Please login to comment.
Latest blogs
Telemetry correlation for Scheduled Jobs in Optimizely

I previously demonstrated how to correlate telemetry to Azure Application Insights within a Hangfire job. But how about those jobs that are built a...

Stefan Holm Olsen | Mar 23, 2023 | Syndicated blog

Fixing Optimizely Content Syncing/Caching Issues on the DXP pre CMS.Core 12.13.0

Hi all, With our recent deployments to the DXP for .NET 6 projects (one a new build and one an upgrade) our clients had raised issues where there...

Scott Reed | Mar 23, 2023

Handle hostnames, schedule jobs and role access when synchronizing content

The Environment Synchronizer module helps you to set your environment into a known state after synchronizing databases between environments. In thi...

Ove Lartelius | Mar 23, 2023 | Syndicated blog

4 tips and tricks for Hangfire on Optimizely CMS

Here are four useful tricks I always apply to any site where I use Hangfire (code included).

Stefan Holm Olsen | Mar 21, 2023 | Syndicated blog