Microsoft Dependency Injection Documentation - c#

In the documentation for dependency injection I notice the following line.
The MVC framework will automatically look at the service provider to
register our dependency in the Controller.
They then provide a basic example with constructor injection, not their example but in essence this.
public class Example
{
private IFooFactory foo;
public Example(IFooFactory foo) => this.foo = foo;
public void SampleUse()
{
using(var context = foo.Create())
context.DoSomething();
}
}
If you have a console application, by default it will not look at the service provider to register your dependency with the concrete implementation. Is there a way to simulate that? Otherwise the console application will require you to do something along these lines:
public static Main(string[] args)
{
// Stuff to prepare the application and build service provider.
var service = serviceProvider.GetService<IFooFactory>();
using(var context = service.Create())
context.DoSomething();
// OR
var fooFactory = serviceProvider.GetService<IFooFactory>();
new Example(fooFactory).SampleUse();
}
Which creates the problem of having to pass IFooFactory or pulling things into the main that you may wanted separated for structure. How can I make the console application look at the provider when a new class is created with a defined interface?

You have to create everything manually as the framework is not there to automagically do it for you.
var services = new ServiceCollection();
services.AddTransient<IFooFactory, FooFactory>();
services.AddTransient<Example>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
Example example = serviceProvider.GetService<Example>();
example.SampleUse();
While not ideal, it is usually the way shown in most examples where DI is configured manually.
When you inspect the framework DI integration, behind the scenes it does the exact same thing during startup.
You could probably write your own code to inspect available types, but that is a very broad task to tackle on your own.
Reference Dependency injection in ASP.NET Core
Default service container replacement
The built-in service container is meant to serve the needs of the
framework and most consumer apps. We recommend using the built-in
container unless you need a specific feature that it doesn't support.
Some of the features supported in 3rd party containers not found in
the built-in container:
Property injection
Injection based on name
Child containers
Custom lifetime management
Func<T> support for lazy initialization

Related

Resolving dependency injected service as part of builder when specifying options

I'm using Microsoft.Extensions.DependencyInjection in my ASP.NET Core project (targeting .NET 7.0).
I have a service that, provided a sizable number of injected other services, yields a string value that I need in order to populate an options method during my DI registrations. Typically, I'd simply have DI inject the service into any of the controllers in which I'd pull the various values needed, but here the situation is a bit different.
Here, I am using one of those many helpful extension methods of IServiceCollection that themselves register their own various types, but it also exposes an action that allows me to specify some settings. I need to resolve a string value from my aforementioned service that I can use in the option specification method later on.
This extension method isn't something I have written, but part of a third-party library and it itself is quite extensive (e.g. not something I want to write/maintain my own version of). The extension itself looks like the following:
builder.Services.AddMySpecialService().SpecifyOptions(opt => {
opt.Id = "<Insert DI string value here>";
});
Ideally, I need to inject the service in such a way so as to pass that string value into my settings, but short of creating a local instance (not really feasible given all its own dependencies), I'm at a loss of how I'd go about this, if it's even possible at all.
Has anyone successfully done this and if so, how? Thanks!
Without knowing what that third-party library is, you can use dependencies when configuring your options in a standard way.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder
.Services
.AddSingleton<IStringProviderService, StringProviderService>()
.AddOptions<MyOptions>()
// For .Configure() method you can specify up to 5 dependencies.
.Configure<IStringProviderService>(
(myOptions, stringProviderService) =>
{
myOptions.Id = stringProviderService.GetString();
}
);
public class MyOptions
{
public required string Id { get; set; }
}
public interface IStringProviderService
{
string GetString();
}
public class StringProviderService : IStringProviderService
{
string IStringProviderService.GetString()
{
return Guid.NewGuid().ToString("N");
}
}

Using IDataProtectionProvider in test project?

When using IDataProtectionProvider in a Web API, the IoC container is configured with AddDataProtection (services.AddDataProtection();) and enables the use of DI to retrieve a IDataProtectionProviderin a service as such:
private readonly IDataProtectionProvider _dataProtectionProvider;
public CipherService(IDataProtectionProvider dataProtectionProvider)
{
_dataProtectionProvider = dataProtectionProvider;
}
If I would like to test my CipherService (in my case using Xunit), I will not be able to make this work without using DI, so my question is;
Q: How can I use DI or otherwise make IDataProtectionProvider in a test project?
Here how I did it using Moq framework:
Mock<IDataProtector> mockDataProtector = new Mock<IDataProtector>();
mockDataProtector.Setup(sut => sut.Protect(It.IsAny<byte[]>())).Returns(Encoding.UTF8.GetBytes("protectedText"));
mockDataProtector.Setup(sut => sut.Unprotect(It.IsAny<byte[]>())).Returns(Encoding.UTF8.GetBytes("originalText"));
Mock<IDataProtectionProvider> mockDataProtectionProvider = new Mock<IDataProtectionProvider>();
mockDataProtectionProvider.Setup(s => s.CreateProtector(It.IsAny<string>())).Returns(mockDataProtector.Object);
And where I need to pass in the IDataProtectionProvider, I use:
mockDataProtectionProvider.Object
For an integration test scenario, where you want a real DataProtectionProvider, you can use the following MSDN Documentation article.
Hope this helps.
EphemeralDataProtectionProvider can be used in a unit testing scenario as it generates a random secret for each instance.
Example:
var dataProtectionProvider = new EphemeralDataProtectionProvider();
var service = new CipherService(dataProtectionProvider);
// test as usual
This was specifically provided by Microsoft for your exact use-case.
There are scenarios where an application needs a throwaway IDataProtectionProvider. For example, the developer might just be experimenting in a one-off console application, or the application itself is transient (it's scripted or a unit test project). To support these scenarios the Microsoft.AspNetCore.DataProtection package includes a type EphemeralDataProtectionProvider. This type provides a basic implementation of IDataProtectionProvider whose key repository is held solely in-memory and isn't written out to any backing store.

Why is an ASP.NET-Core app 'Configuration/AppSettings' POCO passed around as IOptions<T> instead of just T? [duplicate]

It seems to me that it's a bad idea to have a domain service require an instance of IOptions<T> to pass it configuration. Now I've got to pull additional (unnecessary?) dependencies into the library. I've seen lots of examples of injecting IOptions all over the web, but I fail to see the added benefit of it.
Why not just inject that actual POCO into the service?
services.AddTransient<IConnectionResolver>(x =>
{
var appSettings = x.GetService<IOptions<AppSettings>>();
return new ConnectionResolver(appSettings.Value);
});
Or even use this mechanism:
AppSettings appSettings = new AppSettings();
Configuration.GetSection("AppSettings").Bind(appSettings);
services.AddTransient<IConnectionResolver>(x =>
{
return new ConnectionResolver(appSettings.SomeValue);
});
Usage of the settings:
public class MyConnectionResolver
{
// Why this?
public MyConnectionResolver(IOptions<AppSettings> appSettings)
{
...
}
// Why not this?
public MyConnectionResolver(AppSettings appSettings)
{
...
}
// Or this
public MyConnectionResolver(IAppSettings appSettings)
{
...
}
}
Why the additional dependencies? What does IOptions buy me instead of the old school way of injecting stuff?
Technically nothing prevents you from registering your POCO classes with ASP.NET Core's Dependency Injection or create a wrapper class and return the IOption<T>.Value from it.
But you will lose the advanced features of the Options package, namely to get them updated automatically when the source changes as you can see in the source here.
As you can see in that code example, if you register your options via services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); it will read and bind the settings from appsettings.json into the model and additionally track it for changes. When appsettings.json is edited, and will rebind the model with the new values as seen here.
Of course you need to decide for yourself, if you want to leak a bit of infrastructure into your domain or pass on the extra features offered by the Microsoft.Extensions.Options package. It's a pretty small package which is not tied to ASP.NET Core, so it can be used independent of it.
The Microsoft.Extensions.Options package is small enough that it only contains abstractions and the concrete services.Configure overload which for IConfiguration (which is closer tied to how the configuration is obtained, command line, json, environment, azure key vault, etc.) is a separate package.
So all in all, its dependencies on "infrastructure" is pretty limited.
In order to avoid constructors pollution of IOptions<>:
With this two simple lines in startup.cs inside ConfigureServices you can inject the IOptions value like:
public void ConfigureServices(IServiceCollection services)
{
//...
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddScoped(cfg => cfg.GetService<IOptions<AppSettings>>().Value);
}
And then use with:
public MyService(AppSettings appSettings)
{
...
}
credit
While using IOption is the official way of doing things, I just can't seem to move past the fact that our external libraries shouldn't need to know anything about the DI container or the way it is implemented. IOption seems to violate this concept since we are now telling our class library something about the way the DI container will be injecting settings - we should just be injecting a POCO or interface defined by that class.
This annoyed me badly enough that I've written a utility to inject a POCO into my class library populated with values from an appSettings.json section. Add the following class to your application project:
public static class ConfigurationHelper
{
public static T GetObjectFromConfigSection<T>(
this IConfigurationRoot configurationRoot,
string configSection) where T : new()
{
var result = new T();
foreach (var propInfo in typeof(T).GetProperties())
{
var propertyType = propInfo.PropertyType;
if (propInfo?.CanWrite ?? false)
{
var value = Convert.ChangeType(configurationRoot.GetValue<string>($"{configSection}:{propInfo.Name}"), propInfo.PropertyType);
propInfo.SetValue(result, value, null);
}
}
return result;
}
}
There's probably some enhancements that could be made, but it worked well when I tested it with simple string and integer values. Here's an example of where I used this in the application project's Startup.cs -> ConfigureServices method for a settings class named DataStoreConfiguration and an appSettings.json section by the same name:
services.AddSingleton<DataStoreConfiguration>((_) =>
Configuration.GetObjectFromConfigSection<DataStoreConfiguration>("DataStoreConfiguration"));
The appSettings.json config looked something like the following:
{
"DataStoreConfiguration": {
"ConnectionString": "Server=Server-goes-here;Database=My-database-name;Trusted_Connection=True;MultipleActiveResultSets=true",
"MeaningOfLifeInt" : "42"
},
"AnotherSection" : {
"Prop1" : "etc."
}
}
The DataStoreConfiguration class was defined in my library project and looked like the following:
namespace MyLibrary.DataAccessors
{
public class DataStoreConfiguration
{
public string ConnectionString { get; set; }
public int MeaningOfLifeInt { get; set; }
}
}
With this application and libraries configuration, I was able to inject a concrete instance of DataStoreConfiguration directly into my library using constructor injection without the IOption wrapper:
using System.Data.SqlClient;
namespace MyLibrary.DataAccessors
{
public class DatabaseConnectionFactory : IDatabaseConnectionFactory
{
private readonly DataStoreConfiguration dataStoreConfiguration;
public DatabaseConnectionFactory(
DataStoreConfiguration dataStoreConfiguration)
{
// Here we inject a concrete instance of DataStoreConfiguration
// without the `IOption` wrapper.
this.dataStoreConfiguration = dataStoreConfiguration;
}
public SqlConnection NewConnection()
{
return new SqlConnection(dataStoreConfiguration.ConnectionString);
}
}
}
Decoupling is an important consideration for DI, so I'm not sure why Microsoft have funnelled users into coupling their class libraries to an external dependency like IOptions, no matter how trivial it seems or what benefits it supposedly provides. I would also suggest that some of the benefits of IOptions seem like over-engineering. For example, it allows me to dynamically change configuration and have the changes tracked - I've used three other DI containers which included this feature and I've never used it once... Meanwhile, I can virtually guarantee you that teams will want to inject POCO classes or interfaces into libraries for their settings to replace ConfigurationManager, and seasoned developers will not be happy about an extraneous wrapper interface. I hope a utility similar to what I have described here is included in future versions of ASP.NET Core OR that someone provides me with a convincing argument for why I'm wrong.
I can't stand the IOptions recommendation either. It's a crappy design to force this on developers. IOptions should be clearly documented as optional, oh the irony.
This is what I do for my configuraition values
var mySettings = new MySettings();
Configuration.GetSection("Key").Bind(mySettings);
services.AddTransient(p => new MyService(mySettings));
You retain strong typing and don't need need to use IOptions in your services/libraries.
You can do something like this:
services.AddTransient(
o => ConfigurationBinder.Get<AppSettings>(Configuration.GetSection("AppSettings")
);
Using Net.Core v.2.2, it's worked for me.
Or then, use IOption<T>.Value
It would look something like this
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
I would recommend avoiding it wherever possible. I used to really like IOptions back when I was working primarily with core but as soon as you're in a hybrid framework scenario it's enough to drive you spare.
I found a similar issue with ILogger - Code that should work across frameworks won't because I just can't get it to bind properly as the code is too dependent on the DI framework.

Need guidance on Autofac custom lifetimescopes vs. multi tenancy

Scenario:
I need to provide different interface implementations to the same interface definitions within the same web application (appdomain) but to different "scopes".
Imagine a simple hierarchical web content structure like this (if you are not familiar with SharePoint):
RootWeb (SPSite) (ctx here)
|______SubWeb1 (SPWeb) (ctx here)
|______SubWeb2 (SPWeb)
|______SubWeb3 (SPWeb)
|_______SubWeb3.1 (SPWeb) (ctx here)
|_______SubWeb3.2 (SPWeb)
RootWeb, SubWeb1 und SubWeb3.1 provide Contexts. That is I implemented an AppIsolatedContext class that is specific for a certain hierarchy level. If a level does not provide a context it inherits the context from the parent node and so on. For example SubWeb3 would inherit its context from RootWeb. SubWeb3.1 however provides its own isolated context.
The isolated context is merely a static ConcurrentDictionary.
Okay so far so good. Now regarding Autofac (I'm new to Autofac and any other DI container - not to the principle of IoC though)... I'm not sure how I correctly set it up to dispose of objects correctly. Actually it shouldn't be that much of an issue because the objects are (once they are created) are supposed to live until the appdomain gets recycled (think of them as a "per isolated context singleton").
I'd be inclined to do something like that:
// For completeness.. a dummy page which creates a "dummy" context
public partial class _Default : Page
{
private static AppIsolatedContext _dummyContainer = new AppIsolatedContext();
public _Default()
{
_dummyContainer.ExceptionHandler.Execute("Test Message");
}
}
// The isolated context which holds all the "context" specific objects
public class AppIsolatedContext
{
public static IContainer Container { get; set; }
public IExceptionHandler ExceptionHandler { get; set; }
//public ISomething Something { get; set; }
//public ISomethingElse SomethingElse { get; set; }
public AppIsolatedContext()
{
// set up autofac
// Create your builder.
ContainerBuilder builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder.RegisterType<MailNotificationHandler>().As<INotificationHandler>();
builder.RegisterType<ExceptionHandler>().As<IExceptionHandler>();
Container = builder.Build();
using (ILifetimeScope scope = Container.BeginLifetimeScope())
{
ExceptionHandler = scope.Resolve<IExceptionHandler>();
//Something = scope.Resolve<ISomething>();
//SomethingElse = scope.Resolve<ISomethingElse>();
}
}
}
Of course my application is not limited to these "context singleton" instances. I will have per request lifetime instances too.. but that's what the ASP.NET integration modules are there for right? I hope they can seamlessly be integrated in SharePoint (2013) too :)
So my question is is it okay what I proposed or do I need to get my hands dirty? If so some direction would be phenomenal...
Digging through Autofac's documentation I stumbled across its multi tenancy capability.
I believe this might suit my purpose as well.. can anyone confirm this?
using System;
using System.Web;
using Autofac.Extras.Multitenant;
namespace DemoNamespace
{
public class RequestParameterStrategy : ITenantIdentificationStrategy
{
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = AppIsolatedContext.Current.Id; // not implemented in the dummy class above, but present in the real thing.
return !string.IsNullOrWhiteSpace(tenantId);
}
}
}
If anything is not crystal - please don't hesitate to tell me :)
Disclaimer: This is a fairly non-trivial question, and given that and my somewhat lack of familiarity with SharePoint 2013, I'll do my best to answer but you'll need to adapt the answer somewhat to your needs.
The way I would structure this is with named lifetime scopes. Rather than contexts with their own containers, use a hierarchy of named scopes. This is how the multitenant support works; it's also how ASP.NET per-web-request support works.
You will first want to read the Autofac wiki page on instance scopes as well as this primer on Autofac lifetimes. Neither of these are small articles but both have important concepts to understand. Some of what I explain here will only make sense if you understand lifetime scope.
Lifetime scopes are nestable, which is how you share singletons or instance-per-web-request sorts of things. At the root of the application is a container with all of your registrations, and you spawn scopes from that.
Container
Child scope
Child of child scope
In a more code related format, it's like this:
var builder = new ContainerBuilder();
var container = builder.Build();
using(var child = container.BeginLifetimeScope())
{
using(var childOfChild = child.BeginLifetimeScope())
{
}
}
You actually resolve components out of scopes - the container itself is a scope.
Key things about lifetime scopes:
You can name them, allowing you to have "singletons" within a named scope.
You can register things on the fly during the call to BeginLifetimeScope.
This is how the multitenant support for Autofac works. Each tenant gets its own named lifetime scope.
Unfortunately, the multitenant support is one-level: Application container spawns tenant-specific "root" scopes, but that's it. Your site hierarchy where you have these contexts has more than one level, so the multitenant support isn't going to work. You can, however, potentially look at that source code for ideas.
What I'd be doing is naming scopes at each level. Each site would get passed an ILifetimeScope from which it can resolve things. In code, it'll look a little like:
var builder = new ContainerBuilder();
// RootWeb will use the container directly and build its per-web-request
// scope from it.
var container = builder.Build();
// Each sub web will get its own scope...
using(var sw1Scope = container.BeginLifetimeScope("SubWeb"))
{
// Each child of the sub web will get a scope...
using(var sw11Scope = sw1Scope.BeginLifetimeScope("SubWeb"))
{
}
using(var sw12Scope = sw1Scope.BeginLifetimeScope("SubWeb"))
{
}
}
Note I'm tagging each level of sub-web scope as "SubWeb" - that will allow you to have "instance per sub web" sort of registrations in both container-level and sub-web-level registrations.
// Register a "singleton" per sub-web:
builder.RegisterType<Foo>()
.As<IFoo>()
.InstancePerMatchingLifetimeScope("SubWeb");
Now, obviously, that's a conceptual thing there - you won't actually be able to wrap everything in using statements like that. You'll need to manage your creation and disposal differently because creation will happen in a different place than disposal.
You can look at both the ASP.NET and multitenant source to get ideas on how to do that. The general algorithm will be:
At application startup, build the root container.
As sub webs start up, spawn a nested lifetime scope named for the sub web.
If a sub web needs a specific component registered, do that during the call to BeginLifetimeScope
If you need the "context" at each sub web level, you'd pass it the scope created for that sub web rather than creating a whole separate container.
Now, you could take it another step by keeping a root-level dictionary of sub web ID to scope so that you'd not need per-level "context" objects at all. It'd be more like a DependencyResolver.Current.GetService<T> kind of pattern. If you look at how the MultitenantContainer in the Autofac multitenant support works, you'll see a similar sort of tenant-ID-to-scope dictionary.
In fact, that multitenant support will be a good pattern to look at, especially if you also want to have per-web-request scopes. The Autofac ASP.NET support requires you pass in a parent ILifetimeScope from which child web request lifetime scopes will be spawned. The multitenant support adds some dynamic aspect in there so when the ASP.NET support calls BeginLifetimeScope the multitenant portion of things automatically figures out (through tenant identification) which tenant should be the parent of the current request. You could do the same thing with your hierarchy of sub-webs. However, again, the multitenant support is a flat structure while your sub webs are a hierarchy, so the multitenant support won't just work.
This is all a long way of saying you have an interesting use case here, but you're going to be getting your hands pretty dirty.

Reference to StructureMap container in concrete type

I'm designing a simple aspects framework using the DynamicProxy stuff and StructureMap and I've run up against an issue. I have the following method in my Registry:
public T AddAspectsTo<T>(T concreteObject)
{
ProxyGenerator dynamicProxy = new ProxyGenerator();
return (T)dynamicProxy.CreateInterfaceProxyWithTargetInterface(typeof(T)
,concreteObject,
new[] { (IInterceptor)new AspectInterceptor(attributeMap) });
}
Which allows me to write code like:
For<ITestClass>().Use<TestClass>().EnrichWith(AddAspectsTo<ITestClass>);
The important thing is that I'm creating a concrete version of AspectInterceptor. In that class I need to grab items from the IoC container, but at this point I don't know about the IContainer object.
I won't need access to the IoC container until the resulting ITestClasses are in use and so the IContainer will have been created, but can't figure out how to grab the instance?
To be clear, I'm talking about cases here where we setup the structuremap container with:
IContainer container = new Container(new ItemWithPropertiesRegistry());
rather than the standard ObjectFactory stuff, which works fine.
The instance to enrich is available via a lambda:
For<ITestClass>().Use<TestClass>().EnrichWith(x => AddAspectsTo<ITestClass>(x));

Categories

Resources