Injecting runtime value into Unity dependency resolver - c#

I am working on a webapi project and using Unity as our IOC container. I have a set of layered dependencies something like the following:
unityContainer.RegisterType<BaseProvider, CaseProvider>(new HierarchicalLifetimeManager());
unityContainer.RegisterType<IRulesEngine, RulesEngine>();
unityContainer.RegisterType<IQuestionController, QuestionController>();
unityContainer.RegisterType<IAPIThing, WebAPIThing>();
Now the constructor for BaseProvider accepts an int as a parameter which is the Case identifier. WebAPIThing takes a BaseProvider in its constructor. Normally in a non web scenario I would inject the case id using something like:
public static IAPIThing GetIAPIThing(int caseId)
{
return CreateUnityContainer().Resolve<IAPIThing >(new ParameterOverride("caseId", caseId).OnType<CaseProvider>());
}
But that only works when I explicitly call that method. In a Web API scenario I am using a
config.DependencyResolver = new UnityDependencyResolver(unityContainer); to resolve my api controllers.
I would guess I will still need to influence how the DependencyResolver resolves that BaseProvider object at runtime.
Anyone had to do something similar?
EDIT 1
I have tried using the following which appears to work:
unityContainer.RegisterType<BaseProvider>(
new HierarchicalLifetimeManager()
, new InjectionFactory(x =>
new CaseProvider(SessionManager.GetCaseID())));

You are trying to inject a runtime value (the case id) into the object graph, which means you are complicating configuration, building, and verification of the object graph.
What you should do is promote that primitive value to its own abstraction. This might sound silly at first, but such abstraction will do a much better job in describing its functionality. In your case for instance, the abstraction should probably be named ICaseContext:
public interface ICaseContext
{
int CurrentCaseId { get; }
}
By hiding the int behind this abstraction we effectively:
Made the role of this int very explicit.
Removed any redundancy with any other values of type int that your application might need.
Delayed the resolving of this int till after the object graph has been built.
You can define this ICaseContext in a core layer of your application and everybody can depend on it. In your Web API project you can define a Web API-specific implementation of this ICaseContext abstraction. For instance:
public class WebApiCaseContext : ICaseContext
{
public int CurrentCaseId
{
get { return (int)HttpContext.Current.Session["CaseId"];
}
}
This implementation can be registered as follows:
unityContainer.RegisterType<ICaseContext, WebApiCaseContext>();
UPDATE
Do note that your own new CaseProvider(SessionManager.GetCaseID()) configuration does not solve all problems, because this means that there must be a session available when verifying the object graph, which will neither be the case during application startup and inside a unit/integration test.

Related

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.

StructureMap and HTTP request-scoped services - why is my service created twice in a single scope?

I have an ASP.NET MVC application using StructureMap.
I have created a service called SecurityContext which has a static Current property. A simplified version looks like this:
public class SecurityContext : ISecurityContext
{
public bool MyProperty { get; private set; }
public static SecurityContext Current
{
get
{
return new SecurityContext() { MyProperty = true };
}
}
}
I've hooked this up in my StructureMap registry as follows:
For<ISecurityContext>().Use(() => SecurityContext.Current);
My understanding of this Linq expression overload of the Use method is that the returned concrete object is the same for the entire HTTP request scope.
However, I've set up a test case where my context interface is injected in two places, once in the controller's constructor and again using the SetterProperty attribute in the base class my view inherits from.
When debugging I observe the Current static method being hit twice so clearly my assumptions are wrong. Can anyone correct what I'm doing here? The reason I want this request-scoped is because I'm loading certain data into my context class from the database so I don't want this to happen multiple times for a given page load.
Thanks in advance.
The default lifecycle for a configuration is Transient, thus each request for an ISecurityContext will create a new instance of SecurityContext. What I think you want is to use the legacy HttpContext lifecycle.
Include the StructureMap.Web nuget package. Then change your configuration to the following:
For<ISecurityContext>()
.Use(() => SecurityContext.Current)
.LifeCycleIs<HttpContextLifecycle>();
More information on lifecyles can be found here.
The HttpContextLifecycle is obsolete, however I do not know if or when it will be removed. The StructureMap team does recommend against using this older ASP.Net lifecycle. They state in the documentation that most modern web frameworks use a nested container per request to accomplish the same scoping. Information about nested containers can be found here.
I don't know if the version of ASP.Net MVC you are using is considered a modern web framework. I doubt it is because ASP.Net Core 1.0 is the really the first in the ASP.Net line to fully embrace the use of DI. However, I will defer to #jeremydmiller on this one.

Unity Dependency Injection - How to create the instance to be injected at runtime

Trying to implement Dependency Injection in an ASP.Net Web API project.
I would like to be able to inject an instance of Account into some of my services.
The Account instance should be created with the users Guid and this is not known until runtime.
So in my service I have:
public TransactionService(Account acc)
{
_account = acc;
}
And in my application startup I can do this - where container is a new UnityContainer:
container.RegisterType<Instanet.Engine.Account>(new InjectionConstructor(new Guid("xxxxxx")));
This, of course, isn't any good as it would be using the same Account for every user/request etc.
If I try to use something like :
container.RegisterType<Instanet.Engine.Account>(new InjectionConstructor(GetTheUsersID()));
... where GetTheUsersID() needs to either examine a cookie or the ASP.Net Identity request it's of course not available in the app startup.
So - Where/How (in simple terms please, this DI stuff is hurting my brain) do I implement this so I can inject an instanced Account into any of the services that may need it.
You generally don't want to mix state and behavior for components that get resolved via the container--DI should be used for components that can be modeled as pure services.
That said, sometimes it makes sense to wrap global or context-specific state in a service component.
In your case, if you only need the UserId locally in a one or more services (in other words, not passing it from one service to another). You mentioned being able to get the UserId from a cookie, so maybe it would look something like:
public class CookieService : ICookieService
{
public int GetCurrentUserId()
{
//pseudo code
return HttpContext.Current.GetCookie["UserId"];
}
}
Now you can inject ICookieService where a UserId is needed.
More complex cases may require an Abstract Factory:
http://blog.ploeh.dk/2012/03/15/ImplementinganAbstractFactory/
If there is only one Account instance possible for the session, then I would create an Account instance in the bootstrap code before all your services are running.
Then you can populate the guid and all other data in your account instance, and register the initialized instance of Account class in Unity via container.RegisterInstance method.
Later it will resolve to what you need.
Does it help?

SimpleInjector - Register Object that depends on values from another registered object

Using SimpleInjector, I am trying to register an entity that depends on values retrieved from another registered entity. For example:
Settings - Reads settings values that indicate the type of SomeOtherService the app needs.
SomeOtherService - Relies on a value from Settings to be instantiated (and therefore registered).
Some DI containers allow registering an object after resolution of another object. So you could do something like the pseudo code below:
container.Register<ISettings, Settings>();
var settings = container.Resolve<ISettings>();
System.Type theTypeWeWantToRegister = Type.GetType(settings.GetTheISomeOtherServiceType());
container.Register(ISomeOtherService, theTypeWeWantToRegister);
SimpleInjector does not allow registration after resolution. Is there some mechanism in SimpleInjector that allows the same architecture?
A simple way to get this requirement is to register all of the available types that may be required and have the configuration ensure that the container returns the correct type at run time ... it's not so easy to explain in English so let me demonstrate.
You can have multiple implementations of an interface but at runtime you want one of them, and the one you want is governed by a setting in a text file - a string. Here are the test classes.
public interface IOneOfMany { }
public class OneOfMany1 : IOneOfMany { }
public class OneOfMany2 : IOneOfMany { }
public class GoodSettings : ISettings
{
public string IWantThisOnePlease
{
get { return "OneOfMany2"; }
}
}
So let's go ahead and register them all:
private Container ContainerFactory()
{
var container = new Container();
container.Register<ISettings, GoodSettings>();
container.RegisterAll<IOneOfMany>(this.GetAllOfThem(container));
container.Register<IOneOfMany>(() => this.GetTheOneIWant(container));
return container;
}
private IEnumerable<Type> GetAllOfThem(Container container)
{
var types = OpenGenericBatchRegistrationExtensions
.GetTypesToRegister(
container,
typeof(IOneOfMany),
AccessibilityOption.AllTypes,
typeof(IOneOfMany).Assembly);
return types;
}
The magic happens in the call to GetTheOneIWant - this is a delegate and will not get called until after the Container configuration has completed - here's the logic for the delegate:
private IOneOfMany GetTheOneIWant(Container container)
{
var settings = container.GetInstance<ISettings>();
var result = container
.GetAllInstances<IOneOfMany>()
.SingleOrDefault(i => i.GetType().Name == settings.IWantThisOnePlease);
return result;
}
A simple test will confirm it works as expected:
[Test]
public void Container_RegisterAll_ReturnsTheOneSpecifiedByTheSettings()
{
var container = this.ContainerFactory();
var result = container.GetInstance<IOneOfMany>();
Assert.That(result, Is.Not.Null);
}
As you already stated, Simple Injector does not allow mixing registration and resolving instances. When the first type is resolved from the container, the container is locked for further changes. When a call to one of the registration methods is made after that, the container will throw an exception. This design is chosen to force the user to strictly separate the two phases, and prevents all kinds of nasty concurrency issues that can easily come otherwise. This lock down however also allows performance optimizations that make Simple Injector the fastest in the field.
This does however mean that you sometimes need to think a little bit different about doing your registrations. In most cases however, the solution is rather simple.
In your example for instance, the problem would simply be solved by letting the ISomeOtherService implementation have a constructor argument of type ISettings. This would allow the settings instance to be injected into that type when it is resolved:
container.Register<ISettings, Settings>();
container.Register<ISomeOtherService, SomeOtherService>();
// Example
public class SomeOtherService : ISomeOtherService {
public SomeOtherService(ISettings settings) { ... }
}
Another solution is to register a delegate:
container.Register<ISettings, Settings>();
container.Register<ISomeOtherService>(() => new SomeOtherService(
container.GetInstance<ISettings>().Value));
Notice how container.GetInstance<ISettings>() is still called here, but it is embedded in the registered Func<ISomeOtherService> delegate. This will keep the registration and resolving separated.
Another option is to prevent having a large application Settings class in the first place. I experienced in the past that those classes tend to change quite often and can complicate your code because many classes will depend on that class/abstraction, but every class uses different properties. This is an indication of a Interface Segregation Principle violation.
Instead, you can also inject configuration values directly into classes that require it:
var conString = ConfigurationManager.ConnectionStrings["Billing"].ConnectionString;
container.Register<IConnectionFactory>(() => new SqlConnectionFactory(conString));
In the last few application's I built, I still had some sort of Settings class, but this class was internal to my Composition Root and was not injected itself, but only the configuration values it held where injected. It looked like this:
string connString = ConfigurationManager.ConnectionStrings["App"].ConnectionString;
var settings = new AppConfigurationSettings(
scopedLifestyle: new WcfOperationLifestyle(),
connectionString: connString,
sidToRoleMapping: CreateSidToRoleMapping(),
projectDirectories: ConfigurationManager.AppSettings.GetOrThrow("ProjectDirs"),
applicationAssemblies:
BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray());
var container = new Container();
var connectionFactory = new ConnectionFactory(settings.ConnectionString);
container.RegisterSingle<IConnectionFactory>(connectionFactory);
container.RegisterSingle<ITimeProvider, SystemClockTimeProvider>();
container.Register<IUserContext>(
() => new WcfUserContext(settings.SidToRoleMapping), settings.ScopedLifestyle);
UPDATE
About your update, if I understand correctly, you want to allow the registered type to change based on a configuration value. A simple way to do this is as follows:
var settings = new Settings();
container.RegisterSingle<ISettings>(settings);
Type theTypeWeWantToRegister = Type.GetType(settings.GetTheISomeOtherServiceType());
container.Register(typeof(ISomeOtherService), theTypeWeWantToRegister);
But please still consider not registering the Settings file at all.
Also note though that it's highly unusual to need that much flexibility that the type name must be placed in the configuration file. Usually the only time you need this is when you have a dynamic plugin model where a plugin assembly can be added to the application, without the application to change.
In most cases however, you have a fixed set of implementations that are already known at compile time. Take for instance a fake IMailSender that is used in your acceptance and staging environment and the real SmptMailSender that is used in production. Since both implementations are included during compilation, allowing to specify the complete fully qualified type name, just gives more options than you need, and means that there are more errors to make.
What you just need in that case however, is a boolean switch. Something like
<add key="IsProduction" value="true" />
And in your code, you can do this:
container.Register(typeof(IMailSender),
settings.IsProduction ? typeof(SmtpMailSender) : typeof(FakeMailSender));
This allows this configuration to have compile-time support (when the names change, the configuration still works) and it keeps the configuration file simple.

Unity -- using information from request to resolve dependencies

I've recently refactored my MVC application to use Unity dependency injection to resolve dependencies, which is great. It's much more decomposable, etc., etc.
What I'm doing now is adding the capability for multiple tenants to use it. The approach I'm using (so that the rest of the code doesn't have to know much about the tenants) is creating things like a tenant-filtered version of my repository interface (which is just a proxy for another repository... so it will call one of the underlying methods, then check if the record has the right tenant and behave accordingly). This lets me basically emulate having a totally separate store for each tenant even though under the hood the data is not segregated, so relatively little of the client code needs to change.
The problem with all of this is how it fits into the DI way of doing things. What I'm planning to do is, at the beginning of the request, detect the host name, then use that to determine the tenant (each tenant will have a list of hostnames in the DB). Although I'm using per-request lifetimes for most objects Unity is constructing and resolving I don't really get how Unity can "know" what tenant to use since it would need both the data about the request (which I suppose the controller will have, but I don't think is available in my container configuration method) and access to the database to know which host (and it hardly seems desirable to have my container configuration making database calls). I can solve #2 by only passing in a host name and making the classes with tenants go figure out which tenant is being referenced, but that doesn't help with #1.
Right now I'm using "property injection" (also known as "a public property" in less high-falutin' circles), but I don't see how I'm going to avoid having my controller be the one that actually feeds the tenant data in, so now I don't really have just the one composition root controlling everything.
Is there a way I can do this in the composition root, or should I just resign myself to having the controller do this work?
For some reason you seem to forget about injection factories. Registering interface/type against a factory lets you execute arbitrarily complicated code upon resolving, including consulting the request, tenant database, whatever.
container.RegisterType<IRepository>(
new InjectionFactory(
c => {
// whatever, consult the database
// whatever, consult the url
return ...;
} );
The factory composition is transparent so that whenever you need it, the target doesn't even know that the factory code has been executed rather than a type instance from simple mapping.
Somewhere it needs to make a database call. Maybe the simplest place would be in global.ascx if it's needed system wide.
private static ConcurrentDictionary<string, string> _tenantCache = new ConcurrentDictionary<string, string>();
protected virtual void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
var tenantId = _tenantCache.GetOrAdd(app.Context.Request.Url.Host, host =>
{
// Make database call in this class
var tenant = new TenantResolver();
return tenant.GetTenantId(host);
})
app.Context.Items["TenantID"] = tenantId ;
}
You will want to cache the result as Application_BeginRequest is called alot. You can then configure Unity to have child containers. Put all the common/default mappings in the parent container then create a child container per tenant and register the correct implementation for each tenant in it's own child container.
Then implement IDependencyResolver to return the correct child container.
public class TenantDependencyResolver : IDependencyResolver
{
private static IUnityContainer _parentContainer;
private static IDictionary<string, IUnityContainer> _childContainers = new Dictionary<string, IUnityContainer>();
public TenantDependencyResolver()
{
var fakeTenentID = "localhost";
var fakeTenentContainer = _parentContainer.CreateChildContainer();
// register any specific fakeTenent Interfaces to classes here
//Add the child container to the dictionary for use later
_childContainers[fakeTenentID] = fakeTenentContainer;
}
private IUnityContainer GetContainer()
{
var tenantID = HttpContext.Current.Items["TenantID"].ToString();
if (_childContainers.ContainsKey(tenantID)
{
return _childContainers[tenantID];
}
return _parentContainer;
}
public object GetService(Type serviceType)
{
var container = GetContainer();
return container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
var container = GetContainer();
return container.ResolveAll(serviceType);
}
}
Then set ASP.NET MVC DependecyResolver to be the TenantDependencyResolver. I didn't run this code but it should give you an idea of what you would need to do. If your implementations are set then you might be able to do it in the static constructor of TenantDependecyResolver.

Categories

Resources