Umbraco 9

To build Health Valley's new website, we use Umbraco 9, which is the latest version of the most user-friendly CMS at the time of writing. We like Umbraco 9.

The biggest change .NET 5 and ASP.NET Core

Compared to Umbraco 8, Umbraco 9 has many beneficial new features. The biggest change is the use of a new framework: .NET 5 and ASP.NET Core. After all, the framework that Umbraco previously used, .NET Framework, is no longer being developed by Microsoft.

The benefits

The introduction of .NET 5 in Umbraco has several advantages. For example, consider the fact that .NET 5 offers cross-platform development, allowing you to develop your Umbraco website on Linux, macOS, or Windows.

Dependency injection

.NET 5 features, such as dependency injection, are also supported. This makes the code less complex, as as much unnecessary code as possible is omitted. For example, you can choose to inject services into your Razor views.

Configuration

In addition to dependency injection, we also use the configuration that .NET 5 offers, which allows us to store certain configuration values. For example, this can be used in combination with User Secrets to securely store sensitive data, such as API keys. After all, sensitive information should not be available to unauthorised persons.

The code example below demonstrates the use of configuration in .NET 5. In our Health Valley project, we have a link with SalesForce, which stores customer-related data. In addition, you can also opt to wrap the configuration settings in a class, a so-called POCO (Plain Old CLR Object).

private readonly string _clientId;
private readonly string _clientSecret;
private readonly string _loginEndpoint;
private readonly string _password;
private readonly string _username;

public SalesforceClient(IConfiguration configuration)
{
   _loginEndpoint = configuration.GetValue<string>("SalesForce:loginEndpoint");
   _username = configuration.GetValue<string>("SalesForce:username");
   _password = configuration.GetValue<string>("SalesForce:password");
   _clientId = configuration.GetValue<string>("SalesForce:clientId");
   _clientSecret = configuration.GetValue<string>("SalesForce:clientSecret");
}

Library Examine example

In addition to .NET 5 features, Umbraco 9 offers multiple dependencies that have been updated. One example is the Examine library, based on Lucene.net, which supports search functionality within Umbraco websites. In our experience, the new version of Examine works very well. At the time of writing, there is only a shortage of documentation, which makes implementing some Examine features more difficult. However, it is only a matter of time before the documentation for the new version is released.

Below is a piece of sample code related to Examine. Using dependency injection, the iExamineManager can be retrieved, which retrieves a search index.

public class ExamineService
{
   private readonly IExamineManager _examineManager;

   public ExamineService(IExamineManager examineManager)
   {
       _examineManager = examineManager;
   }

   public ISearchResults SearchBySearchTerm(string searchTerm, string indexName)
   {
       if (!_examineManager.TryGetIndex(indexName, out var index))
       {
           throw new InvalidOperationException("Index was not found.");
       }

       var searcher = index.Searcher;
      
       return !string.IsNullOrEmpty(searchTerm)
           ? searcher.Search(searchTerm)
           : searcher.CreateQuery().All().Execute();
   }
}

Performance and notification system

The new version of Umbraco is also a great piece of technology from the user's point of view. The performance of Umbraco 9 sites compared to older Umbraco sites is much better.

In addition, the new notification system improves the user experience. Such a notification acts as a kind of webhook. For example, you can use the ContentPublishingNotification, which executes the provided code when a piece of content is published.

public class LogImportantAnnouncement
{
   private readonly ILogger _logger;

   public LogImportantAnnouncement(ILogger logger)
   {
       _logger = logger;
   }

   public void Handle(ContentPublishingNotification notification)
   {
       foreach (var entity in notification.PublishedEntities)
       {
           if (!entity.ContentType.Alias.Equals("announcement")) continue;
          
           var announcementCategory = entity.GetValue<string>("category");

           if (announcementCategory.Equals("important"))
           {
               _logger.Information($"Important announcement: {entity.Id}");
           }
       }
   }
}

In previous versions of Umbraco, events were used for this purpose. Although the two ways of working do not differ much functionally, there are differences in how notifications are created compared to events.

For example, notifications can be registered using the IumbracoBuilder, which makes it easy to register them as services in the ConfigureServices method.

public static class UmbracoBuilderNotificationExtensions
{
   public static IUmbracoBuilder AddAnnouncementNotifications(this IUmbracoBuilder builder)
   {
       builder.AddNotificationHandler<ContentPublishingNotification, LogImportantAnnouncement>();

       return builder;
   }
}
public void ConfigureServices(IServiceCollection services)
{
   services.AddUmbraco(_env, _config)
       .AddBackOffice()
       .AddWebsite()
       .AddComposers()
       .AddAnnouncementNotifications()
       .Build();
}

As a team, we are very satisfied with the performance, the clear architecture of the code and the functionalities that Umbraco 9 brings!

Written by: Luuk Janssens, Certified Umbraco developer

Getting to know

Heb je vragen? Of wil je samen sparren?

We denken graag met je mee hoe jouw organisatie digitaal kan versnellen. Of het nu gaat om een UX, technische uitdaging of AI oplossingen. Stuur een berichtje en we nemen zsm contact met je op.