Using Umbraco page based configurations in Services
Umbraco now supports .NET’s underlying IConfiguration
feature i.e. appSettings.json / environment variables / key vaults / etc… which is a great feature. However I found myself in need of a configuration source from a page in Umbraco. In case you store for example settings on your Home page and and you have various services that require the values of these settings you have a number of options to do this including:
- Reading the configuration values from your Controllers, passing them on to your services methods as parameters
- Reading the configuration values from the node directly from the service using an injected
IUmbracoHelper
orIUmbracoContextAccessor
But I found that in my case I did not like either of these options and wanted to have something that’s similar to .NET’s IOptions
support. After intensive Googling I still found nothing, so I had to come up with a solution of my own.
I added a custom Configuration type i.e., SearchOptions
and define that as a singleton, only to be created once when first required:
public class SearchOptions
{
public int? MyCustomPageId { get; internal set; }
}
public void ConfigureServices(IServiceCollection services)
{
#pragma warning disable IDE0022 // Use expression body for methods
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
.Build();
#pragma warning restore IDE0022 // Use expression body for methods
services.AddTransient<ISearchService, SearchService>();
services.AddSingleton<SearchOptions>(sp =>
{
var ctx = sp.GetService<IUmbracoContextAccessor>();
var fallback = sp.GetService<IPublishedValueFallback>();
var firstNode = ctx.GetRequiredUmbracoContext().Content.GetAtRoot().FirstOrDefault();
var home = new HomePage(firstNode, fallback);
return new SearchOptions { MyCustomPageId = home.MyCustomPage?.Id };
});
}
With that I could extend my service and have that object injected i.e.
public class SearchService : ISearchService
{
private readonly SearchOptions _options;
public SearchService(
SearchOptions options)
{
_options = options;
}
...
}
Because the SearchOptions
is added as a Singleton it means that the logic that reads the homepage is only performed once in the lifetime of the application and you don’t have to worry about performance consequences or having to cache it.
That’s it, I hope this helps someone.