BridgedOptions 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package BridgedOptions --version 1.0.0                
NuGet\Install-Package BridgedOptions -Version 1.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BridgedOptions" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add BridgedOptions --version 1.0.0                
#r "nuget: BridgedOptions, 1.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install BridgedOptions as a Cake Addin
#addin nuget:?package=BridgedOptions&version=1.0.0

// Install BridgedOptions as a Cake Tool
#tool nuget:?package=BridgedOptions&version=1.0.0                

Bridged Options

Getting Started

You can find this packages via NuGet: https://www.nuget.org/packages/BridgedOptions

Overview

There are situations where you wish to intercept the options and perform additional operations. One example is when you have encrypted values stored in the appsettings and need to decrypt them in code, in order to call some service.

Within the .net framework there already exists a hook to do this - the IConfigureOptions interface. This mutates the existing loaded options which may be considered as a code smell, as well as being more difficult to provide interface segregation - in which the same options may be split into different usages via interfaces.

In this scenario, it would be better to not change the existing options but rather return a new object, with any changes applied. This also allows you to have the interface segregation (if you desired).

All of this is achieved by using the bridge pattern. This pattern uncouples the desired options interface from the source via a bridging class. This allows you to perform any extra logic before returning your bridged version, without the need to mutate the original options.

Also you do not need to expose your new concrete object, just your interface as your returning type can be defined within your bridge as a nested class.

Simple Example

Given the following options class:

[BridgeViaType(typeof(AccountBridgeOptions))]
public sealed class AccountOptions
{
    public string Username { get; set; }
    public string Password { get; set; }
}

You decorate the options that is used to load appsettings with an attribute defining your bridge. The bridge class can look like:

public sealed class AccountBridgeOptions : IBridgeOptions<AccountOptions, IAccountInfo>
{
    public IAccountInfo BridgeFrom(AccountOptions source)
    {
        return new AccountInfo
        {
            Username = source.Username,
            Password = source.Password
        };
    }

    private sealed class AccountInfo : IAccountInfo
    {
        public string Username { get; init; }
        public string Password { get; init; }
    }
}

where the interface IAccountInfo is:

public interface IAccountInfo
{
    string Username { get; }
    string Password { get; }
}

Finally we need to register our options with an extension method in the startup:

services.AddOptionsBridge<AccountOptions, IAccountInfo>(configuration.GetSection("Account"));

This assumes that you appsettings has a section like:

{
  "Account": {
    "Username": "homers",
    "Password": "51mp50n5"
  }
}

The above now means that you can inject the IAccountInfo into any class, as required. You can also benefit from injecting other services into the bridge class too. The options are still registered as normal so if you wish to still use IOptions<T> then this still works.

Along with the above extension for IOptions there are two other extensions for the IOptionsSnapshot<T> and IOptionsMonitor<T> if required.

Developer Notes

Building and Publishing

From the root, to build, run:

dotnet build --configuration Release

To run all the unit and integration tests, run:

dotnet test --no-build --configuration Release

To create the packages, run (optional as the build generates the packages):

cd src/BridgedOptions
dotnet pack --no-build --configuration Release

To publish the packages to the nuget feed on nuget.org:

dotnet nuget push ./bin/Release/BridgedOptions.1.0.0.nupkg -k [THE API KEY] -s https://api.nuget.org/v3/index.json
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.2 385 10/12/2021
1.0.1 309 10/8/2021
1.0.0 320 10/8/2021

Added support for the dependency injection NuGet package