Using a custom Service Fabric configuration provider with ASP.NET Core

Authored by Mike Wasson (AzureCAT). Reviewed by Vaclav Turecek. Edited by Nanette Ray and RoAnn Corbisier.

This sample shows how to expose Service Fabric configuration settings to ASP.NET Core, using the ASP.NET Core configuration API. You can find the sample files on GitHub at ServiceFabric-AspNetCore-Sample.

ASP.NET Core uses configuration providers to load application settings at runtime. This sample implements a custom configuration provider for Service Fabric, so that an ASP.NET Core service can use the Service Fabric configuration model.

This article assumes that you are familiar with both Service Fabric and ASP.NET Core. For more information, see Build a web service front end for your application using ASP.NET Core.

To create a configuration provider, we'll derive from the ConfigurationProvider class.

 public class ServiceFabricConfigurationProvider : ConfigurationProvider

Service Fabric stores settings in configuration packages that are accessible through the Service Fabric runtime. Overload the ConfigurationProvider.Load method to load settings from a configuration package:

 public override void Load()
{
    var config = _context.GetConfigurationPackageObject(_packageName);
    LoadPackage(config);
}

private void LoadPackage(ConfigurationPackage config, bool reload = false)
{
    if (reload)
    {
        Data.Clear();  // Clear the old keys on reload
    }
    foreach (var section in config.Settings.Sections)
    {
        foreach (var param in section.Parameters)
        {
            Data[$"{section.Name}:{param.Name}"] = param.IsEncrypted ? param.DecryptValue().ToUnsecureString() : param.Value;
        }
    }
}

Service Fabric automatically loads the Settings.xml configuration file, but a configuration package can contain arbitrary files in any format. If you use your own file, the Service Fabric API just gives you the file path. To support other file types, you would need to parse the file and turn it into a dictionary of key/value pairs.

It's possible to upgrade a service's configuration package without changing the code package. In that case, Service Fabric does not restart the service. Instead, the service receives a ConfigurationPackageModifiedEvent event to notify it that the package changed. We can hook into that event by setting an event handler in the constructor of our provider:

 public ServiceFabricConfigurationProvider(string packageName)
{
    _packageName = packageName;
    _context = FabricRuntime.GetActivationContext();
    _context.ConfigurationPackageModifiedEvent += (sender, e) =>
    {
        this.LoadPackage(e.NewPackage, reload: true);
        this.OnReload(); // Notify the change
    };
}

A service can have more than one configuration package, so we pass the package name in the constructor.

The event handler calls our private LoadPackage method with the value true for the reload parameter. Then it calls the OnReload method, which is defined in the base class. This method notifies the ASP.NET Core configuration system that the values have changed.

The next thing that's needed is a configuration source, which acts as a factory for the configuration provider.

 public class ServiceFabricConfigSource : IConfigurationSource
{
    public string PackageName { get; set; }

    public ServiceFabricConfigSource(string packageName)
    {
        PackageName = packageName;
    }
 
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new ServiceFabricConfigurationProvider(PackageName);
    }
}

Finally, we create an extension method that registers the configuration source with the configuration API:

 public static class ServiceFabricConfigExtensions
{
    public static IConfigurationBuilder AddServiceFabricConfig(this IConfigurationBuilder builder, string packageName)
    {
        return builder.Add(new ServiceFabricConfigSource(packageName));
    }
}

Call this extension method in the ASP.NET Core Startup method:

 public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddServiceFabricConfig("Config") // Add Service Fabric configuration settings.
        .AddEnvironmentVariables();
    Configuration = builder.Build();
}

Now the ASP.NET Core service can access the Service Fabric configuration settings just like any other application settings. For example, you can use the options pattern to load settings into strongly typed objects:

 public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration);  // Strongly typed configuration object.
    services.AddMvc();
}

That's it! Find the complete sample on GitHub at ServiceFabric-AspNetCore-Sample.

   

See Also