Last active
October 25, 2020 22:03
-
-
Save Carl-Hugo/161d2948d430028f0cb07442ab17c740 to your computer and use it in GitHub Desktop.
2020-10-25-Options-DavidF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net5.0</TargetFramework> | |
<LangVersion>preview</LangVersion> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0-rc.2.20475.5" /> | |
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0-rc.2.20475.5" /> | |
<PackageReference Include="Xunit" Version="2.4.1" /> | |
</ItemGroup> | |
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// To run: `dotnet run` (should display `All Good!`) | |
// Requires .NET 5 SDK | |
// Uses C# 9 preview features | |
// | |
using System; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Options; | |
using Xunit; | |
var services = new ServiceCollection(); | |
// Configure MyOptions and consumers | |
services.Configure<MyOptions>(x => new MyOptions { Name = "Whatever" }); | |
services.Configure<MyOptions>("MagicName", x => new MyOptions { Name = "MagicName" }); | |
services.AddTransient<MeControlOptionsLifetimeSingleton>(); | |
services.AddTransient<MeControlOptionsLifetimeScoped>(); | |
services.AddTransient<MeDontControlOptionsLifetime>(); | |
services.AddTransient<MeControlOptionName>(); | |
// This is an example of how to bind MyOptions to an "IOptionsWhatever<T>" | |
// This could be anything that would make sense for any given concrete scenario | |
services.AddTransient<MyOptions>(sp => sp.GetRequiredService<IOptionsMonitor<MyOptions>>().CurrentValue); | |
// Using the registered stuff just for fun :) | |
var serviceProvider = services.BuildServiceProvider(); | |
var meControlOptionsLifetimeSingleton = serviceProvider.GetRequiredService<MeControlOptionsLifetimeSingleton>(); | |
var meControlOptionsLifetimeScoped = serviceProvider.GetRequiredService<MeControlOptionsLifetimeScoped>(); | |
var meDontControlOptionsLifetime = serviceProvider.GetRequiredService<MeDontControlOptionsLifetime>(); | |
var meControlOptionName = serviceProvider.GetRequiredService<MeControlOptionName>(); | |
// Making sure that all is rigged correctly (while at it) | |
Assert.Same(meControlOptionsLifetimeSingleton.Options.CurrentValue, meDontControlOptionsLifetime.Options); | |
Assert.NotSame(meControlOptionsLifetimeSingleton.Options.CurrentValue, meControlOptionsLifetimeScoped.Options.Value); | |
Assert.NotSame(meControlOptionName.Options, meControlOptionsLifetimeSingleton.Options.CurrentValue); | |
Console.WriteLine("All Good!"); | |
// Some options | |
public class MyOptions | |
{ | |
public string Name { get; set; } | |
} | |
// This class controls the lifetime of its MyOptions dependency. | |
// By injecting a IOptionsMonitor<T>, MeControlOptionsLifetimeSingleton decides that it wants a singleton lifetime. | |
// To change the lifetime of that MyOptions, we must update MeControlOptionsLifetimeSingleton | |
// Not IoC | |
public record MeControlOptionsLifetimeSingleton(IOptionsMonitor<MyOptions> Options); | |
// This class controls the lifetime of its MyOptions dependency. | |
// By injecting a IOptionsSnapshot<T>, MeControlOptionsLifetimeScoped decides that it wants a scoped lifetime. | |
// To change the lifetime of that MyOptions, we must update MeControlOptionsLifetimeScoped | |
// Not IoC | |
public record MeControlOptionsLifetimeScoped(IOptionsSnapshot<MyOptions> Options); | |
// This class don't control the lifetime of its MyOptions dependency. | |
// By injecting MyOptions directly, MeDontControlOptionsLifetime lets the composition root manage the MyOptions's lifetime. | |
// To change the lifetime of that MyOptions, we must update the composition root (a good thing) | |
// Yes: IoC | |
public record MeDontControlOptionsLifetime(MyOptions Options); | |
// This class controls the lifetime of its MyOptions dependency. | |
// This class controls what instance of MyOptions is "created" (by name). | |
// To change the lifetime of that MyOptions, we must update MeControlOptionName | |
// To change the created instance of MyOptions, we must update MeControlOptionName (change "MagicName" by something else) | |
// Not IoC | |
public class MeControlOptionName | |
{ | |
public MyOptions Options { get; } | |
public MeControlOptionName(IOptionsFactory<MyOptions> factory) | |
{ | |
Options = factory.Create("MagicName"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment