I am looking for simple approaches to the use of the Options pattern for mixes of environment-agnostic, environment-specific and secret configuration in .NET Core. I have seen unnecessarily complex approaches to this, and developed one approach which feels much simpler than what I have seen, but still begs to be simplified further. I will provide that in the first answer to this question.
So, put as a clear question:
What is the simplest approach to Binding Options objects to Configuration sections in .NET Core that is a consistent approach across all types of .NET Core projects, e.g. Function apps, Worker services, ASP.NET Core, etc?
Bonus questions:
How can this approach be used without requiring the use of a Dependency Injection container?
creating an instance of IConfiguration with a Dependency Injection container feels very messy to me in that IConfiguration then needs to be a parameter of every constructor within a chain of dependencies, or it requires that all class/interface implementations need to be registered within the DI container.
How can this approach be used with a Dependency Injection container?
most people I've met do use DI containers (either Autofac or the .NET Core DI container) so it's definitely worth discussing how the approach might also be useful in a DI container scenario.
===========
It's worth noting that I completely adhere to the Dependency Inversion principle via Dependency Injection, but do so via chained constructors (typically two) and only minimally use DI containers in .NET Core - almost always for logging only. There are a number of reasons for this which are probably best stated by Ygor Bugayenko in Elegant Objects and not the topic of this post.
===========
One more thing:
I am not going to accept my own answer that I'm providing below. In fact, I'm not going to accept an answer for awhile so that there is plenty of time for alternate approaches to be provided in the answers.
Looking forward to your ideas! Cheers
One approach to this is to create Options objects that lazy-initialize, and use an implementation of IConfiguration that has been stored in a singleton at startup that is available to the entire application in order to eliminate the need for DI container gymnastics. I believe that the following approach does not diverge from Microsoft's intent regarding the use of the Options pattern, but is a different and IMO simpler approach to doing so.
In this example implementation I'm going to use naive Singleton patterns for simplicity - if you're concerned at all with multiple threads creating multiple instances you might go with the use of the Lazy class or a traditional double-locking singleton pattern.
I'll use a RemoteCache configuration object as an example of an Options compliant model:
public class RemoteCache
{
private const string SectionName = "Redis";
private static RemoteCache _instance;
private static readonly Redis RedisConfig = new();
public static RemoteCache Instance()
{
if (_instance is not null) return _instance;
_instance = new RemoteCache();
return _instance;
}
private RemoteCache() { }
public string CacheConnection => RedisConfigInstance.CacheConnection;
public string CacheKey => RedisConfigInstance.CacheKey;
private Redis RedisConfigInstance
{
get
{
if (string.IsNullOrWhiteSpace(RedisConfig.CacheConnection) is false) return RedisConfig;
AppConfiguration.Instance.GetSection(SectionName).Bind(RedisConfig);
return RedisConfig;
}
}
private class Redis
{
public string CacheConnection { get; set; } = string.Empty;
public string CacheKey { get; set; } = string.Empty;
}
}
Q. What is AppConfiguration and where does this get initialized?
A. A static class that gets initialized in your Startup class.
My Startup class for a function app typically looks like this. You might notice that I am using "appsettings.json" which is typically not done in function apps, but I wanted the environment-agnostic portion of my configuration to follow the same pattern used in non-function-apps, rather than shoving dang-near everything into Environment Variables which seems pretty typical of function apps and leads to a glut of environment variables being pushed in during the deployment process. I do use environment variables for secrets in non-local deployments, and use KeyVault references to acquire those secrets at runtime. When running locally, secrets are acquired using the UserSecrets.
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.SetBasePath(executionContextOptions.AppDirectory)
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json", false)
.AddJsonFile("local.settings.json", true)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true);
AppConfiguration.Instance = configurationBuilder.Build();
builder.Services.AddLogging(logging =>
{
logging.AddApplicationInsights(new ApplicationInsightsConfiguration().AppInsightsInstrumentationKey());
}
}
}
This is all the AppConfiguration class is:
public static class AppConfiguration
{
public static IConfiguration Instance;
}
So, once you have your startup code and AppConfiguration class in place you can happily create Options model objects that map to your configuration sections to your heart's content. These models are implemented as singletons so you can then access them from whatever code needs configuration no matter how deeply nested in your application.
Usage example:
(I prefer accessing configuration models through an interface, which allows my code to be TDD with true unit tests that use fakes of config implementations [of course, use mocks if you prefer])
public interface IRemoteCacheConfiguration
{
string CacheConnection();
string RedisCacheKey();
}
public class RemoteCacheConfiguration : IRemoteCacheConfiguration
{
public string CacheConnection() => RemoteCache.Instance().CacheConnection;
public string RedisCacheKey() => RemoteCache.Instance().CacheKey;
}
public class MyThingThatAccessesTheCache
{
private readonly IRemoteCacheConfiguration _remoteCacheConfiguration;
public MyThingThatAccessesTheCache() : this(new RemoteCacheConfiguration()) { }
public MyThingThatAccessesTheCache(IRemoteCacheConfiguration remoteCacheConfiguration) => _remoteCacheConfiguration = remoteCacheConfiguration;
public void DoStuff()
{
string cacheConnection = _remoteCacheConfiguration.CacheConnection();
}
}
Related
This question is similar to my previous question about Razor Components, but instead, this question is about Razor Pages, which requires a different interception point.
I am making an ASP.NET Core application using the Pure DI approach explained in the book Dependency Injection Principles, Practices, and Patterns (DIPP&P). Part of my application has a web API controller. To implement Pure DI with my controller, I was easily able to follow section 7.3.1 "Creating a custom controller activator" from DIPP&P to create a controller activator class, similar to the example found in DIPP&P. This was done by implementing IControllerActivator and composing my composition root within the create method.
My application will also feature Razor Pages. I would like to continue using the Pure DI approach but I cannot find any examples on how to do this. My assumption is I need to create a RazorPageActivator class, which implements IRazorPageActivator and add my composition root to the Activate method. However, after reviewing the RazorPageActivator class found in the ASP.NET Core GitHub, it looks very complex and I fear if I intercept it (or override it?) by making my own class that implements IRazorPageActivator things will break and I'll be in a mess.
My question is how does one go about implementing Pure DI with Razor Pages, if possible?
With Razor Pages, the IPageModelActivatorProvider functions as your Composition Root's Composer. Here's an example based on the default Visual Studio (2019) Razor Pages project template.
Let's start with the custom IPageModelActivatorProvider, which acts as your Composer, which is part of your Composition Root:
public class CommercePageModelActivatorProvider
: IPageModelActivatorProvider, IDisposable
{
// Singletons
private readonly ILoggerFactory loggerFactory;
public CommercePageModelActivatorProvider(ILoggerFactory loggerFactory) =>
this.loggerFactory = loggerFactory;
public Func<PageContext, object> CreateActivator(
CompiledPageActionDescriptor desc) =>
c => this.CreatePageModelType(c, desc.ModelTypeInfo.AsType());
public Action<PageContext, object> CreateReleaser(
CompiledPageActionDescriptor desc) =>
(c, pm) => (pm as IDisposable)?.Dispose();
private object CreatePageModelType(PageContext c, Type pageModelType)
{
// Create Scoped components
var context = new CommerceContext().TrackDisposable(c);
// Create Transient components
switch (pageModelType.Name)
{
case nameof(IndexModel):
return new IndexModel(this.Logger<IndexModel>(), context);
case nameof(PrivacyModel):
return new PrivacyModel(this.Logger<PrivacyModel>());
default: throw new NotImplementedException(pageModelType.FullName);
}
}
public void Dispose() { /* Release Singletons here, if needed */ }
private ILogger<T> Logger<T>() => this.loggerFactory.CreateLogger<T>();
}
Notice a few things with this implementation:
The structure of this class is very similar to the one's given in the book's code samples.
It implements IDisposable to allow disposing of its own created singletons. In this case, no singletons are created in its constructor, so nothing needs to be disposed. The ILoggerFactory is "externally owned"; it is created by the framework, and will be disposed (if needed) by the framework.
The class uses a custom TrackDisposable extension method (shown later on) that allows tracking scoped and transient dependencies. The TrackDisposable method will add those instances to the request and allows the framework to dispose them when the request ends.
This is why the CreateReleaser method only disposes the Page itself. The disposing of all other created components is done by the framework when you track them for disposal. You can also choose to track the Page itself; in that case you can leave the CreateReleaser delegate empty.
There is a handy Logger<T>() method that simplifies the creation of ILogger<T> implementations. Those come from the framework and are created by the ILoggerFactory.
Here's the TrackDisposable extension method:
public static class DisposableExtensions
{
public static T TrackDisposable<T>(this T instance, PageContext c)
where T : IDisposable
{
c.HttpContext.Response.RegisterForDispose(instance);
return instance;
}
}
The last missing piece of infrastructure required is the registration of your CommercePageModelActivatorProvider into the framework's DI Container. This is done inside the Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// Register your custom component activator here
services.AddSingleton<
IPageModelActivatorProvider, CommercePageModelActivatorProvider>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}
Until now, I have used the Unity IOC container to resolve dependencies, which works just fine. With the Unity DI, I normally resolve instances in the following way:
Public class TestClass {
public TestClass()
{
var instance = IOC.resolve<InterfaceClassToResolve>();
}
}
This works great, but seeing that .net core now provides me with an out of the box DI container, I would much rather like to use that - There is just one problem compared to the Unity IOC, namely that it is injected as a constructor argument, and not resolved like the example above.
In most cases, I figured that it forces me to chain my dependencies throughout multiple classes, instead of just resolving my dependency in the classes that actually needs them.
I have been looking at ways to solve this, and as far as I can see, the only option is to do something like this:
Public class TestClass {
public TestClass(IServiceProvider serviceProvider)
{
var instance = serviceProvider.GetService<InterfaceClassToResolve>();
}
}
And then we are back to square one again...
Therefore, am I missing some of the functionality behind the .net core IOC, or is there some secret sauce to why most examples wants me use the .net core IOC via constructor arguments?
You can use DI without constructors like:
On the ConfigureServices
services.AddSingleton<YourClass>()
Then inject it like this:
private YourClass YourClass
{
get
{
return this.serviceProvider.GetRequiredService<YourClass>();
}
}
As already commented, Service Locator pattern is not the best method and considered an anti-pattern.
I understand the necessity, though, of finding a way to easily convert existing code to the out-of-the-box DI system without going mad.
I therefore suggest you to do something like this:
1) Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DatabaseContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// other services configuration here
// IMPORTANT: This should be the last line of ConfigureServices!
IOC.CurrentProvider = services.BuildServiceProvider();
}
...
2) IOC.cs
public class IOC
{
public static IServiceProvider CurrentProvider { get; internal set; }
public static T resolve<T>()
{
return CurrentProvider.GetService<T>();
}
}
This should allow you to use dotnet core DI with existing service locator code based on Unity, with minimal fixes (basically just some using declarations to be fixed), as long as you solemnly promise to refactor your code as soon as possible to get rid of all that Service Locator code :D
I am using ASP.NET.Core to embed a web server into a large legacy desktop application. My middleware components need to reference pre-existing application objects.
With difficulty I have got this working using the native DI container, but the resulting code is extraordinarily obtuse and opaque.
What I would really like to do, is to explicitely inject the dependencies, which are specific pre-existing object instances, through constructor parameters. The auto-magic of the DI container isn't giving me any benefits, just a lot of pain!
Is it possible to use ASP.NET.Core without the DI Container?
Here's some simplified code to illustrate my current solution:
class Dependency
{
public string Text { get; }
public Dependency(string text) => Text = text;
}
class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly Dependency _dep1;
private readonly Dependency _dep2;
public MyMiddleware(RequestDelegate next, Dependency dep1, Dependency dep2)
{
_next = next;
_dep1 = dep1;
_dep2 = dep2;
}
public Task InvokeAsync(HttpContext context)
{
return context.Response.WriteAsync(_dep1.Text + _dep2.Text);
}
}
Startup and application code:
class Startup
{
private readonly Dependency _dep1;
private readonly Dependency _dep2;
public Startup(Dependency dep1, Dependency dep2)
{
_dep1 = dep1;
_dep2 = dep2;
}
public void Configure(IApplicationBuilder appBuilder)
{
appBuilder.UseMiddleware<MyMiddleware>(_dep1, _dep2);
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dep1 = new Dependency("Hello ");
var dep2 = new Dependency("World");
int port = 5000;
StartWebServer(port, dep1, dep2);
Process.Start($"http://localhost:{port}");
}
void StartWebServer(int port, Dependency dep1, Dependency dep2)
{
IWebHostBuilder builder = new WebHostBuilder();
builder.UseUrls($"http://0.0.0.0:{port}/");
builder.UseKestrel();
builder.ConfigureServices(servicesCollection => servicesCollection.AddSingleton(new Startup(dep1, dep2)));
builder.UseStartup<Startup>();
IWebHost webHost = builder.Build();
var task = webHost.StartAsync();
}
}
Can this sample code be refactored to eliminate the DI container?
There is no way to completely remove the built-in DI Container from ASP.NET Core, since it’s completely integrated in the whole process; everything depends on its existence. That built-in container is part of the larger configuration API that ASP.NET Core provides.
This means that as application developer, in one way or another, you will have to interact with it at some point, when it comes to changing default behavior.
This doesn't mean, though, that you are forced to use the built-in DI Container, or in fact use any container, to build up object graphs of application components. Building object graphs without the use of a DI Container is a quite common practice called Pure DI, and this is, for the most part, possible as well when using ASP.NET Core.
If you wish to practice Pure DI, it typically means replacing a few common interception points. One such common interception point is the IControllerActivator abstraction. By replacing the default implementation, you can intercept the creation of MVC controller instances, which are typically the root objects of your application's object graphs. Here is an example Github repository that demonstrates how to apply Pure DI with respect to creating controllers.
In your example, however, you only seem to deal with custom middleware. In that case, using Pure DI is even simpler, because it doesn't require replacing factory abstractions, such as IControllerActivator. This can be done as follows:
var middleware = new MyMiddleware(_dep1, _dep2);
app.Use((context, next) =>
{
return middleware.InvokeAsync(context, next);
});
Notice how I moved the RequestDelegate out of the MyMiddleware constructor into the InvokeAsync method. Reason for doing this, is that makes it possible to create MyMiddleware independently of any runtime values. RequestDelegate is a runtime value and in the previous example, MyMiddleware is just created once at startup. In other words, it's simply a Singleton.
In case MyMiddleware does contain some mutable state, and therefore can’t be cached indefinitely (for instance because it depends on a DbContext), you can create it inside the delegate. This means it will be created once per request.
I am currently trying to get my head around structuremap now that the ObjectFactory static function has been marked as obsolete.
In the long run I have to use this in a MVC and WebApi application. When previously used, a line to a static method was placed in the the global.asax to initialise everything using the ObjectFactory.
ObjectFactory.Initialize{
container.For .....
}
Trying to convert this to the new IContainer approach I have come up with the following however am wondering if I have actually inadvertently implemented this often mentioned Anti-Pattern in my approach.
Static method to return container:
public class StructureMapConfig
{
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
}
Userservice's contstructor looks like this:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IStringService _stringService;
public UserService(IUserRepository userRepository, IStringService stringService)
{
_userRepository = userRepository;
_stringService = stringService;
}
Finally the initialise (this instance in a console app) looks somthing like this:
private static IUserService _userService;
private static IContainer _container;
static void Main(string[] args)
{
_container = StructureMapConfig.GetContainer();
_userService = _container.GetInstance<IUserService>();
}
So to my questions.
Am I doing anything seriously wrong here
In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.
Is returning the IContainer from the static method the best approach
If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.
Thanks for any advice.
To go through your questions in order:
Am I doing anything seriously wrong here
No, I don't see anything seriously wrong here. There are a few improvements you could make that I'll talk about shortly.
In the UserService, should I be passing the IContainer in and using
the object factory to get the instance or should I leave as is.
You're correct in injecting UserService over an instance of IContainer. If your controller only requires the UserService then why inject the entire container. Really you only want to inject the bare minimum of what you need to reduce unnecessary coupling and dependencies.
Is returning the IContainer from the static method the best approach
Within the removal of the ObjectFactory then yes, returning an instance of the container via a static method is a common approach for those classes whose creation is not managed via MVC's Dependency Resolution.
If this was a MVC app, is it best practice to build this once in the
Global.asax or should the controller constructor call the static
method every time.
Creating the container in Global.asax.cs is your best approach as it's done once on Application_Start, however see below for my recommendation of using a nested container per http request.
Improvements:-
Take advantage of StructureMap's registries:
Instead of referencing the dependencies directly like this:
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
Opt to use StructureMap's registries instead. This way you can group your dependencies (such as MVC specific dependencies or WebAPI specific dependencies, like so:
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserService>().Use<UserService>();
this.For<IStringService>().Use<StringService>();
this.For<IUserRepository>().Use<UserRepository>();
}
}
Then load your registries like this:
container.Configure(c => {
c.IncludeRegistry<WebsiteRegistry>();
c.IncludeRegistry<TaskRegistry>();
});
HTTP Context bound containers:
Another recommended pattern when using StructureMap with ASP.NET MVC or WebApi (or any HTTP based application) is to use nested containers that are bound to each HTTP request. This basically involves creating a new nested container on each HTTP request and then disposing it at the end of the request. This ensures that dependencies such as session objects, database connections, or UoW contexts are disposed of as soon as the HTTP request is over.
I would recommend taking a look over this article which goes into more detail on the matter and talks about how this can be set up.
This is exactly the same technique that's used in the StructureMap.MVC5 package that's often recommended by StructureMap's creator, Jeremy Miller.
Auto registering dependencies
Instead of registering every dependency with StructureMap manually you can take advantage of StructureMap's auto-registration. You can also specify your own scanning conventions.
I am writing a plugin as part of a plugin architecture. The way plugins are created is via reflection and CreateInstance. Therefore the default constructor is called. This code I cannot touch and I am trying to find a sensible way to use DI without the ability to use a framework.
I believe I have 3 options:
i) Poor Man's DI (PMDI)
ii) Factory Pattern
iii) TinyIOC or similar (one cs file that handles DI)
I started looking at PMDI but then a dependency needed another dependency so I ended up with something similar to this which is ugly and could get worse:
public MyMainPluginClass() : this(new Repo(new Logger()))
{
}
public MyMainPluginClass(IRepo repo)
{
}
I then moved onto the idea of a Factory Pattern but could not find any decent demo code. I assume I would have something like this:
public static FactoryUtility
{
public static IRepo GetRepo()
{
return new Repo(GetLogger());
}
public static ILogger GetLogger()
{
return new Logger();
}
}
public MyMainPluginClass() : this(FactoryUtility.GetRepo())
{
}
public MyMainPluginClass(IRepo repo)
{
}
Is that how it would look?
I then came across TinyIOC which is one class that does all the dependency registering but I believe it requires to be setup in a Program.cs which I don't have in a class library. If someone has any experience using this could it be used like so:
public MyMainPluginClass()
{
var container = TinyIoCContainer.Current;
container.AutoRegister();
var implementation = container.Resolve<IRepo>();
MyMainPluginClass(implementation);
}
public MyMainPluginClass(IRepo repo)
{
}
Are there any alternative approaches to achieve DI without using a 3rd party library and if not which approach would choose from above?
NOTE: The code above has not been compiled and is just an idea of what I think would work. Please post corrections if they are valid approaches.
Since you're using .NET 4, you might want to consider using MEF, as it's built into the framework itself. This looks like fairly straightforward DI, which MEF handles well, as it's intended mainly for extensibility.
For details, see the Learn More page on the MEF CodePlex site.
I went with TinyIOC in the end. Unfortunately the plugin's constructor gets called several times before its actually up and running. I simply set a boolean to prevent registration being called several times and therefore it allows me to simply auto-register dependencies and off we go.
public MyMainPluginClass() : this(FactoryUtility.SetupIOC())
{
}
public MyMainPluginClass(IRepo repo)
{
}
public static class FactoryUtility
{
private static bool Initialized = false;
public static IRepo SetupIOC()
{
var container = TinyIoCContainer.Current;
if (!Initialized)
{
container.AutoRegister(new[] { Assembly.GetExecutingAssembly() });
Initialized = true;
}
var result = container.Resolve<IRepo>();
return result;
}
}
If I absolutely don't want to add a dependency to a DI container, I like to use my own TinyIOC (sorry about the name, didn't know it was taken), which for small projects gives me the same semantics as using a container, but clocks in at below 200 LOC.
If you are interested, here is the code: https://gist.github.com/ad7608e2ae10b0f04229