Kentico 2020: The Phoenix and .NET Core
The next version of Kentico EMS, which will be Kentico 2020 and has a pre-production name of "Phoenix", will usher in a new era for Kentico ๐ค.
Kentico's Portal Engine development architecture will be removed completely, Kentico's core libraries will target .NET Standard 2.0, and Kentico itself will support .NET Core (and therefore ASP.NET Core) ๐.
These are some major changes (and depending on your perspective, bigger than Kentico 12's move to ASP.NET MVC 5).
Kentico 2020 will likely be released, with a full suite of features, in November of 2020 (if past releases set any precedent).
But why, you ask, is Sean writing about Kentico 2020 when this blog series is about Kentico 12 ๐ค?!
Well there is a pretty simple answer. Unless we want our Kentico 12 sites to always run on Kentico 12, at some point, we will be upgrading them to Kentico 2020.
Below, I'd like to detail some recommendations to prepare all of us for that eventual effort, laying the groundwork now to help our future selves look back on us with kinder eyes ๐.
Adopt Kentico + MVC
Since Kentico 2020 won't support Portal Engine, building a site in Portal Engine with Kentico 12 means that there isn't going to be an upgrade path - using Portal Engine today is a non-starter (unless you don't plan on upgrading).
If you haven't adopted the awesome Kentico 12 + MVC combo, check out Kentico's documentation on using MVC and all the other blog posts in this series on Kentico 12 Design Patterns.
At this point, Kentico 12 has been out for well over a year, so there are many other Kentico developers writing blog posts about their experiences with MVC, and the community on DevNet is always happy to help ๐ช.
Don't Rely on Removed Kentico EMS Features
Along with Portal Engine development, Kentico EMS is going to be removing several other features in Kentico 2020.
Most of the features are strongly tied to Portal Engine development, so if we are doing Kentico 12 + MVC then we probably don't have much to worry about.
But we should be familiar with the list anyway to save ourselves some heartache ๐ later.
There's also been discussions of "Related Pages" potentially being removed in Kentico 14 (or whatever comes after Kentico 2020). This is definitely not set in stone, but knowing this kind of stuff well in advance is a great reason to frequent DevNet and follow Kentico on Twitter to stay in-the-know ๐.
Write MVC 5 Code Like It's ASP.NET Core
Although a lot looks the same when comparing MVC 5 running on ASP.NET to ASP.NET Core, there are many things that have changed.
While we could go looking for the new ASP.NET Core-ish way of doing things when we upgrade our code, it might be easier to do this ahead of time.
Don't Use System.Web.Optimization
When it comes to managing client-side dependencies in ASP.NET MVC 5, the standard approach has been to leverage the types found in the System.Web.Optimization namespace.
However, that code hasn't been updating since 2014 and both CSS and JavaScript have changed significantly since then.
I've run into cases where MVC started throwing exceptions (when trying to bundle and minify) because it couldn't understand my modern ES2015+ JavaScript, despite the fact that Edge/Chrome/Firefox/Safari all ran it without issue ๐ฃ.
Avoid the types in this namespace where possible and adopt alternative approaches to managing client-side dependencies, like the ones I mention in my post about managing front-end dependencies or Vue.js with Kentico 12 below ๐ค.
Kentico 12: Design Patterns Part 5 - Front-End Dependency Management
Sean G. Wright ใป Jun 17 '19 ใป 8 min read
Kentico 12: Design Patterns Part 16 - Integrating Vue.js with MVC
Sean G. Wright ใป Oct 21 '19 ใป 14 min read
Use Dependency Injection / IoC Container
While MVC 5 supports Dependency Injection using a custom Inversion of Control (Ioc) Container like Autofac, ASP.NET Core requires it for framework types and strongly encourages it for developer's custom code ๐ฎ.
Kentico's MVC 5 documentation explains Dependency Injection and how to set it up, so we already have all the tools we need to get started down this path, today ๐.
Note: We can even add Dependency Injection to the CMS, check out my blog post Kentico 12: Design Patterns Part 4 - Adding Dependency Injection to the CMS to find out how ๐ง.
Use async
/await
Where Possible
While MVC 5 supports C#'s async
/await
syntax (which leads to performance gains when handling many HTTP requests concurrently), it's kinda apparent that support was added after-the-fact.
ASP.NET Core, however, takes a async
/await
-first approach from the beginning ๐ช!
This means that it's no longer a question of worrying about synchronous calls to async code resulting in deadlocks ๐ฑ.
Async code should be async from top to bottom, and since ASP.NET Core allows and encourages developers to adopt this pattern, let's do it where it brings easy wins.
It should be noted that sometimes we have to use what we're given and we need to rely on what's provided in ASP.NET MVC 5, even though we know it's not there in ASP.NET Core.
For these scenarios there's another option...
Isolate ASP.NET Behind Abstractions
The move to MVC for Kentico 12 has brought about a lot of new framework features to leverage, NuGet packages to consume, and namespaces to add using
s for.
These parts of MVC are great because they help us get our work done, but they are a double-edged sword - they can be a liability ๐.
ASP.NET MVC 5 was built on System.Web
and a large part of the original motivation behind ASP.NET Core was to get away from System.Web
(it was modeled after ASP.NET Web API's independence of System.Web
using OWIN ๐คฏ).
This means any code that relies on System.Web
could see its types moved, or worse, removed in ASP.NET Core โน.
A lot of MVC 5 features are still in ASP.NET Core, but because of the changes, my advice is to put your use of ASP.NET specific types behind abstractions.
What would this look like ๐ค?
Classes like System.Web.UrlHelper
, System.Web.Routing.RouteCollection
, and especially System.Web.HttpContext
can be put behind custom interfaces that we create, instead of being spread throughout our codebase.
Below is an example:
public interface IUrlBuilder
{
string BuildUrl(
string actionName,
string controllerName,
object routeValues);
}
public class MVCUrlBuilder : IUrlBuilder
{
public string BuildUrl(
string actionName,
string controllerName,
object routeValues)
{
var requestContext = HttpContext.Current.Request.RequestContext;
var urlHelper = new UrlHelper(requestContext);
return urlHelper.Action(
actionName,
controllerName,
routeValues,
Uri.UriSchemeHttps);
}
}
This might seem like a weird thing to do since we created a new interface and class to do the same things that UrlHelper
already did.
However, if we use this interface (along with Inversion of Control and Dependency Injection) throughout our codebase, we've removed a dependency on UrlHelper
and HttpContext
(both of which are in System.Web
) ๐.
As a side bonus, by removing dependencies on things like HttpContext
, our code becomes a lot more unit testable ๐ช.
I cover this topic further in my blog post Kentico 12: Design Patterns Part 1 - Writing Testable Code.
Kentico 12: Design Patterns Part 1 - Writing Testable Code
Sean G. Wright ใป Jun 1 '19 ใป 7 min read
Write Automated Integration and End-to-End Tests
On the topic of tests, an upgrade from ASP.NET MVC 5 to ASP.NET Core is likely going to involve a lot of moving pieces, especially if it's being performed at the same time as a Kentico upgrade.
How can we ensure that our app's behavior still reflects the expectations of the stakeholders? How can we make this kind of change without disrupting the business and site visitors, from a functionality perspective ๐คทโโ๏ธ?
Integration tests can go a long way towards ensuring that business logic behavior is well defined, the units of our code play nice together, and this verification can be automated and reproducible ๐.
If we need more guarantees, end-to-end (E2E) tests can prove that the sign-up form or checkout experience is functioning as required, despite the fact that we've just pulled the framework-as-tablecloth out from underneath the dishes.
Never written an integration test? Learn how in my post Kentico 12: Design Patterns Part 8 - Setting Up Integration Tests.
Kentico 12: Design Patterns Part 8 - Setting Up Integration Tests
Sean G. Wright ใป Jul 22 '19 ใป 10 min read
Check Our NuGet Dependencies For Compatibility
.NET Standard 2.0 and ASP.NET Core have been out for a little while now (ASP.NET Core is currently at version 3.1) and a large part of the .NET community has updated their libraries and tools to support these newer targets.
However, since the adoption of ASP.NET Core is likely to be a new thing for a lot of Kentico developers, there could be some skeletons in our closets - libraries that are no long maintained or haven't yet been upgraded.
The last thing we want to happen is, halfway through a Kentico upgrade, realize that the library we depend on can't come with us, due to incompatibility, and needs to be replaced ๐.
So, we can check our dependencies now and plan for the future with alternatives if necessary ๐.
Updating Our Internal Libraries
In addition to external library dependencies, we are probably using some libraries that we've written ourselves.
As library authors, there's a couple things that we can do to help prepare for a future of Kentico 2020 built with ASP.NET Core.
Migrate to the SDK-Style .csproj
Format
Along with the changes to the runtime and frameworks, the move to .NET Core brings changes to the tooling.
One that many developers will probably notice is the update to the .csproj
file that defines a .NET project. This new .csproj
format is called is related to the new Common Project System for .NET and is often referred to as SDK-Style ๐ค.
Initially this change was delivered as something specific to .NET Core, but it is also supported for .NET Framework class libraries.
Last year, in my post Kentico 12 Class Libraries with Modern .NET Core Features, I detailed how Kentico developers can start leveraging the new
.csproj
now ๐.
Kentico 12 Class Libraries with Modernย .NET Core Features
Sean G. Wright ใป Jun 1 '19 ใป 15 min read
My favorite way to do this is using Hans van Bakel's CsprojToVs2017 library, however you can also watch this video from Scott Hanselman or perform the upgrade directly in Visual Studio.
The new .csproj
brings many quality-of-life changes for developers, which means it's not just a technical change with no benefit.
There's an old proverb I'm reminded of...
"The best time to update to the SDK-Style project was 3 years ago. The second best time is now" - Sean G. Wright ๐คฃ
Target .NET Standard 2.0 In Our Libraries
While we're updating the project format, we might as well update the target framework!
Since the interop between .NET Core and .NET Framework has lots of sharp edges, and since we can't use System.Web
with ASP.NET Core, upgrading our libraries to .NET Standard 2.0 is a great next step.
Microsoft provides a "portability analyzer" that can show the bits of framework not supported in a library if it were to be upgraded to .NET Core ๐.
If we've managed to isolate those ASP.NET types that don't exist in ASP.NET Core, we might be able to update our libraries without downstream consumers (our Kentico applications) being effected ๐.
In Review
Preparing our Kentico applications for Kentico 2020 can seem daunting! It very well might be if we're tasked with it next year and we didn't formulate a plan.
However, there are several things we can do to put ourselves and our code in the best place possible when that upgrade day comes.
- Adopt Kentico + MVC instead of Portal Engine
- Identify which Kentico EMS features are being removed in Kentico 2020
- Write our MVC 5 code like it's ASP.NET Core
- Avoid
System.Web.Optimization
- Leverage Dependency Injection
- Use
async
/await
from the top -> down in our applications
- Avoid
- Isolate ASP.NET specific types behind abstractions when we need to use them
- Ensure consistent application behavior after upgrades with automated integration and end-to-end tests
- Check 3rd part NuGet dependencies for ASP.NET Core compatibility
- Update our internal libraries
- Migrate to SDK-Style
.csproj
files - Target .NET Standard 2.0 where possible
- Migrate to SDK-Style
Wow, that was a lot! If you haven't read any of my Kentico blog posts before, this could be like drinking from the firehose ๐๐ฅ๐จโ๐.
Fortunately we still have time, before Kentico 2020 is out, to adopt the things I mentioned in this blog post. Maybe it will make for a good starting point to plan your upgrade strategy ๐!
As always, thanks for reading ๐!
If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:
Or my Kentico blog series:
Top comments (1)
It is a great honor to have you write about Kentico product versions and concepts in such detail, you are very deserving of the Kentico 2020 "MVP" title.