Skip to main content

Umbraco Package Migration to .NET Core: Criteria Providers - Migrations

This is one of a series of posts looking at migrating Umbraco packages to V9 and .NET Core. Other posts in this series:

  1. Introduction
  2. A False Start
  3. A Clean Start - Controllers, Services, Configuration and Caching
  4. Criteria Providers - Working With HttpContext
  5. Leaning on Umbraco
  6. Migrating Tests
  7. Extension Methods
  8. Migrations
  9. Wiring It All Up
  10. Distributing and Wrapping Up

Package Distribution

There are at least a couple of ways to distribute Umbraco packages. The original - and still supported in Umbraco V9 - is to create a package through the back-office, selecting the files, schema and content that you wish to include - and saving that into zip file packaged according to a custom format. This file can be uploaded to our.umbraco.com, from where it can be downloaded by other users for install on their projects, or discovered and installed via the back-office.

The approach that's more common in the .NET space as a whole, is to distribute via NuGet. This has an advantage in terms of better support for dependencies. If there's another library your package depends on, you can define this link in the NuGet file specification.

As a developer and package user, it's this method that I would tend to use if available, so I'm minded to make that the only means of installing the new version of Personalisation Groups. Maybe that's me just feeling lazy at the moment thinking of just one distribution method to maintain, we'll see, but for now I'll need to make sure that NuGet will suffice as a means of distributing the package. The files are clearly no problem, but one benefit of the Umbraco package format is the possibility of including schema and content that will be installed along with the package files.

In order to support that via the NuGet scenario we need to have some code run after package installation, which can use the Umbraco APIs to create the necessary content types, data types and content. I've done this using a migration, which is a managed set of steps used by Umbraco CMS as well as HQ packages such as Umbraco Forms, mostly to carry out database schema changes between verisons. You can run any code though, so it looks like a good solution here.

Using Migrations

Migrations aren't a V9 thing - they exist and are used in V8 - but there's a few changes I ran into worth documenting.

Implementing the Migration

You can see the migration files themselves here and here. And just to caveat... as this whole effor so far mostly a porting of an existing working package, I'm perhaps doing some things a little backward - as I haven't actually got to the point of being able to install and run the code yet. Rather am just getting to a compiling state and with passing unit tests. As such there's likely some errors and perhaps misunderstandings, which I'll clear up as necessary in a later post.

The idea though is that you create a plan class inheriting from MigrationPlan, that references one or more migration steps that inherit from MigrationBase. Each migration step is associated with a key value that's stored in the Umbraco database, so it knows which migrations have run and which, due to an upgrade, need to be run on start-up.

Testing the Migration

I've also written a unit test on the migration, checking that the expected calls to save operations have been made to create the necessary schema and content. You can see it here. One thing worth noting is that I've taken a dependency for the test project on Umbraco.Cms.Tests, which provides some useful base classes and helpers for unit tests. In my case I'm making use of the "builders" available for creating stub model classes - see the CreateRootFolderContent() method - which work by creating sensible defaults for most properties but allowing you to set just what you need.

One thing you'll likely notice is that the migration classes take quite a lot of dependencies - 12 in my example. They don't always need this, but as I'm using Umbraco's services and also creating instances of property editors, all of which themselves have a number of dependencies, the number builds up. This is likely something to just get used to though, as it follows from the promotion of dependency injection we have with .NET Core and now Umbraco V9, that anything the class needs should be injected via the constructor.

Miscellaneous Others

Just a couple of other points worth noting in the migration since the last update:

  • When implementing property editors in C# - see my example here - there's a PropertyEditorAsset attribute that can be used to associated javascript and other client resources. Previously the first argument was an enum defined in a separate library, ClientDependency, but now it's native as Umbraco.Cms.Core.WebAssets.AssetType.
  • There's a few more parameters to pass into the constructor for creating a new property editor, which inherit from DataEditor. All are available from the DI container though and can just be passed in.

Updaing to Alpha 4

Oh, and the official alpha 4 is out! So I updated to use this - upgrading from the version installed from the nightlies to that available on the Umbraco pre-releases NuGet feed at https://www.myget.org/F/umbracoprereleases/api/v3/index.json.

Following Along

The repository containing the code for the migrated package is here. At the time of writing, the state of the migrated code can be seen using this link.

Comments