I am working on a legacy application and my current goal is to set up some integration test which also take use of structure map. So far I had no problem with using SM for unit testing and production code for almost a year. But unfortunately we are forced to use setter injection cos our BOs are real dependency beast (a lot of these objects have circular dependencies on others)
Our workout for this was to use a two step approach: Were we first created all of these objects without inject properties (which cause this circular dependencies) and after wards build up those objects (inject dependency objects through their properties) when they were already created. (See example class A, B and Logic which have circular dependencies)
This worked fine till now ->
When we run lets say 3 integration tests after each other than only the first "turns green" the other test are throwing execptions when structuremap tries to create the instances (in the GetManagerInstances) methods.
I am guessing SM holds its property injection config static.
Definitions
internal interface IM { }
internal interface ILogic { }
internal interface IMA : IM { }
internal interface IMB : IM { }
internal class A : IMA
{
public A() { Console.WriteLine("A"); }
public IMB BInstance { get; set; }
}
internal class B : IMB
{
public B() { Console.WriteLine("B"); }
public IMA AInstance { get; set; }
public ILogic Logic { get; set; }
}
internal class Logic : ILogic
{
public Logic() { Console.WriteLine("Logic"); }
public IMA AInstance { get; set; }
}
Initialization
private static IContainer _container;
while (true)
{
Initialize();
}
internal static void Initialize()
{
_container = new Container(c =>
{
c.For<ILogic>().Singleton().Use<Logic>();
c.For<IMB>().Singleton().Use<B>();
c.For<IMA>().Singleton().Use<A>();
});
// All managers are created and afterwards properties are set to avoid a circular build stack.
List<object> managerInstances = GetManagerInstances();
// After the manager instances are created the dependencies are injected in the properties.
BuildUpManagersUsingPropertyInjection(managerInstances);
}
private static List<object> GetManagerInstances()
{
List<object> managerInstances = new List<object>();
foreach (Type pluginType in new List<Type> { typeof(IMA), typeof(IMB) })
{
try
{
managerInstances.Add(_container.GetInstance(pluginType));
}
catch (Exception ex)
{
// exception on second test run -> see below
}
}
return managerInstances;
}
private static void BuildUpManagersUsingPropertyInjection(List<object> managerInstances)
{
_container.Configure(x => x.SetAllProperties(c =>
{
// configure the property injection for all managers
c.Matching(prop => typeof(IM).IsAssignableFrom(prop.PropertyType));
// client logic is also used by managers
c.TypeMatches(type => type.Equals(typeof(ILogic)));
}));
_container.BuildUp(_container.GetInstance<ILogic>());
managerInstances.ForEach(x => _container.BuildUp(x));
}
Result
StructureMap Exception Code: 295
Bidirectional Dependency Problem
detected with RequestedType:
StructureMapTests.IMA, Name:
237b6fb1-7dee-4f09-b663-c33bb793afc6,
ConcreteType: StructureMapTests.A.
The BuildStack is:
1.) RequestedType: StructureMapTests.IMA, Name:
237b6fb1-7dee-4f09-b663-c33bb793afc6,
ConcreteType: StructureMapTests.A
2.) RequestedType: StructureMapTests.IMB, Name:
ad692281-cd27-493c-8271-3dcf86bacd41,
ConcreteType: StructureMapTests.B
Exception when building
*
Analysis
The output for the First test run is:
A
B
Logic --> Everything OK
The output for the Second test run is:
A
B
Exception when building instances
B
A
Exception when buildinginstances
Logic
A
B --> REPEATING ENDLESS
Please help :(
EDIT
I'm targeting 4.0 .Net framework and using StructureMap release 2.6.2
I have confirmed this is a bug in the current version of StructureMap (as of January 2011). The setter injection policies are in fact being incorrectly shared between containers. The issue has been reported to the StructureMap mailing list.
this does solve the problem with the circular dependency (no exception is thrown when initializing) but the properties are not filled correctly.
A.BInstance = null
B.AInstance = null
Logic.AInstance = null
the properties should be set to the correct instance!
Related
Assuming this use case:
You've got two classes X and Y that depends on a configuration of type Config
public class X
{
public X(IOptions<Config> config)
{
}
}
public class Y
{
public Y(IOptions<Config> config)
{
}
}
Now, you want to create each an instance of X and Y, but with different configurations. What would be the right way to register this?
From everything I read, the only way to solve this would be by adding some sort of "naming" for the different configuration instances and resolve them via a custom resolver:
public delegate Config ServiceResolver(string key);
services.AddTransient<ServiceResolver>(serviceProvider => key =>
{
switch (key)
{
case "A":
return ... (whatever to get the first config instance);
case "B":
return ... (whatever to get the second config instance);
default:
throw new KeyNotFoundException();
}
});
However, this means that the implementation of each X and Y must know about details about how to get the configurations:
They must know the correct name (A or B) and
they must know the ConfigResolver type, which is only an implementation detail/helper class for the sake of dependency injection.
This problem hits even harder if you need to go through several stages of dependencies, like
Config (A) Config (B)
| |
v v
Service Service
| |
v v
X Y
My feeling is, there should be a better way to solve this.
Like some form of receipent dependent service factory:
Host.CreateDefaultBuilder(args).ConfigureServices((context, services) => {
services.Configure<Config>(context.Configuration.GetSection("ConfigA")).For<X>();
services.Configure<Config>(context.Configuration.GetSection("ConfigB")).For<Y>();
});
and maybe
Host.CreateDefaultBuilder(args).ConfigureServices((context, services) => {
services.AddTransient<Service>((services, receiverType) => {
if(receiverType == typeof(X)) {
... resolve a service instance;
}
else {
... resolve some other service instance;
}
});
});
So, is there just some feature I missed until now? Is my understanding of the situation totaly misguided? Or is this really a feature that should be, but has not been added until now?
EDIT:
To make my point clearer: Just assume that X and Y are classes of a third-party library. Their constructors signature cannot be changed by you, as you don't have access to the source code.
So, how would you set this up in a way that you can get each an instance of X with ConfigA and an instance of Y with ConfigB?
Another EDIT 2023-01-02:
Happy new year everyone :)
Seems I have to describe a bit better what's my problem. This is not constrained to IOptions/configurations, but more a general question about where to decide about which service to inject and how it is configured.
Assume I have two a congress location with 2 stages. I call them "bigStage" and "smallStage", but in the end they've got the same implementation. I also got two speakers invited, called "loadSpeaker" and "quietSpeaker", but at this moment in time I don't know which one will speak on which of the two stages.
So I decide I've got this setup:
class Stage {
public Stage(string name, ISpeaker speaker) {
...
}
}
class Speaker: ISpeaker {
public Speaker(string name) {
...
}
}
Now, at the latest time possible, I want to compose my final setup so that I've got 2 Stages (called bigStage and smallStage) and their assigned Speakers (loudSpeaker on bigStage and quietSpeaker on smallStage). This composition/assignment should completely happen in my composition root, so that no code changes have to happen in the rest of my code. How can I do that?
I suggest to use a factory for your Service:
class X {
private readonly Service _service;
public X(ServiceFactory serviceFactory) {
_service = serviceFactory.Create<X>();
}
}
class Service {
private readonly Config _config;
public Service(Config config) { _config = config; }
}
class ServiceFactory {
private readonly IConfiguration _configuration;
/* other Service dependencies would also be injected here */
public ServiceFactory(IConfiguration configuration, /* Service dependencies */) {
_configuration = configuration;
...
}
public Service Create<T>() {
return Create(typeof(T));
}
public Service Create(Type type) {
var configName = switch typeof(T) {
X => "ConfigX",
Y => "ConfigY",
default => throw new Exception()
};
var config = _configuration.GetSection(configName).Get<Config>();
return new Service(config, /* other dependencies */);
}
}
The switch statement can be replaced with a Dictionary<Type, string> or Dictionary<string, string> if you would want to export this dictionary to IConfiguration.
Getting the Config can be also cached for performance (don't forget the thread safety)
So the "trick" to all of this is... you have to piggy back onto ~something to make a decision on which one IMySomething . when you register multiple IMySomething(s).
The factory above where you switch/case on the object.TYPE....is one way.
But it is "fragile", IMHO. Or at the very last, violates the Open/Closed principle of SOLID, as you have to keep editing the code to add a new case-statement.
So I also think you want a Factory.......BUT I do not like "hard coding" the values of the switch/case statements.
So if you follow my IShipper example:
Using a Strategy and Factory Pattern with Dependency Injection
I think you want to create a
IShipperFactory
and inject the IEnumerable of "IShipper"(s).
..
Then you will use your IShipperFactory... when registering your things that need an IShipper.
This does cause a small "ripple" because you need access to the IShipperFactory....to do (later) IoC registrations.
But it would be "clean" and have good separations of concerns.
Let me pseudo code it.
public interface IShipper (from other article)
3 concretes (Usps, FedEx, Ups)
public interface IShipperFactory()
public IShipper GetAnIShipper(string key)
..
public class ShipperFactoryConcrete
(from other article, inject multiple IShippers here)
public IShipper GetAnIShipper(string key)
// look through the injected IShippers to find a match, or else throw exception.
.....
public interface IOrderProcessor
..
public class WestCoastOrderProcessor : IOrderProcessor
/* c-stor */
public WestCoastOrderProcessor(IShipper aSingleShipper)
public class EastCoastOrderProcessor : IOrderProcessor
/* c-stor */
public WestCoastOrderProcessor(IShipper aSingleShipper)
........
Ok, so we decide at compile-time, we want to define the "best" IShipper for the EastCoastOrderProcessor and WestCoastOrderProcessor. (making up some kind of example here)
So need need to IoC register.
from the other article:
cont.RegisterType<IShipper, FedExShipper>(FedExShipper.FriendlyName);
cont.RegisterType<IShipper, UspsShipper>(UspsShipper.FriendlyName);
cont.RegisterType<IShipper, UpsShipper>(UpsShipper.FriendlyName);
now it gets a little "off beaten path".
See:
https://stackoverflow.com/a/53885374/214977
and
// so this is a cart-horse situation, where we need something from the IoC container.... to complete the IoC registrations.
IShipperFactory sf = services.GetRequiredService<IShipperFactory>(); // see https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0#resolve-a-service-at-app-start-up
.. and now we IoC register...but we specify specific values for the constructor. please see the SOF (214977), for syntax-sugar hints. the below is definately pseduo code.....
_serviceCollection.AddSingleton<IOrderProcesor>(x =>
ActivatorUtilities.CreateInstance<EastCoastOrderProcessor>(x, sf.GetAnIShipper(FedExShipper.ShipperName));
);
_serviceCollection.AddSingleton<IOrderProcesor>(x =>
ActivatorUtilities.CreateInstance<WestCoastOrderProcessor>(x, sf.GetAnIShipper(UspsShipper.ShipperName));
);
APPEND:ONE:
Another "trick" .. if you have a code base that you cannot change is.
The "proxy design pattern":
The Proxy design pattern provides a surrogate or placeholder for
another object to control access to it.
https://www.dofactory.com/net/proxy-design-pattern
public EastCoastOrderProcessorProxy
private readonly ThirdPartyOrderProcessor innerThirdPartyOrderProcessor;
public EastCoastOrderProcessor(ThirdPartyOrderProcessor innerThirdPartyOrderProcessor)
{
this.innerThirdPartyOrderProcessor = innerThirdPartyOrderProcessor;
}
..
public WestCoastOrderProcessorProxy
private readonly ThirdPartyOrderProcessor innerThirdPartyOrderProcessor;
public EastCoastOrderProcessor(ThirdPartyOrderProcessor innerThirdPartyOrderProcessor)
{
this.innerThirdPartyOrderProcessor = innerThirdPartyOrderProcessor;
}
So while you cannot change the ThirdPartyOrderProcessor, you can write 1:N wrapper-proxies around it.
The simplest solution I can think of, without using named options inside of your service classes, is moving the selection of the configuration object from the class constructor to the composition root of the application.
This way, your service class simply receives a configuration object as a constructor parameter and it is not aware of the underlying configuration infrastructure.
The composition root, which is in charge of composing the objects which make your application, do know about the configuration infrastructure and picks the right configuration object for your services.
In order to implement this pattern, you need to define an option class as the first step. This option class is needed in order to leverage the options pattern support offered by ASP.NET core. You will only use this class at the composition root level.
public sealed class LayoutOptions
{
public const string Layout = "Layout";
public const string Basic = "Basic";
public const string Complex = "Complex";
public string Name { get; set; } = default!;
public string Color { get; set; } = default!;
public int NumberOfColumns { get; set; }
}
Then you need to define a class which represents the configuration object for your services. This is basically a strongly typed configuration object used to configure your services. This object is built strating from the options class, notice that you don't need to make it identical to the options class itself.
public sealed class LayoutConfiguration
{
public string Name { get; }
public string Color { get; }
public LayoutConfiguration(string name, string color)
{
Name = name;
Color = color;
}
}
Now you need to define your service classes. These types are configured by using the LayoutConfiguration configuration class. Each service class will be properly configured by the composition root of the application, by using the proper named options.
public interface ILayoutService
{
string GetLayoutDescription();
}
public sealed class BasicLayoutService : ILayoutService
{
private readonly LayoutConfiguration _config;
public BasicLayoutService(LayoutConfiguration config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
}
public string GetLayoutDescription() =>
$"Basic layout description. Name: '{_config.Name}' Color: '{_config.Color}'";
}
public sealed class ComplexLayoutService : ILayoutService
{
private readonly LayoutConfiguration _config;
public ComplexLayoutService(LayoutConfiguration config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
}
public string GetLayoutDescription() =>
$"Complex layout description. Name: '{_config.Name}' Color: '{_config.Color}'";
}
You can also defined a couple of controllers, that you can use to test this implementation and be user that your services are wired-up correctly by the composition root of the application:
[ApiController]
[Route("[controller]")]
public sealed class BasicLayoutController : ControllerBase
{
private readonly BasicLayoutService _basicLayoutService;
public BasicLayoutController(BasicLayoutService basicLayoutService)
{
_basicLayoutService = basicLayoutService ?? throw new ArgumentNullException(nameof(basicLayoutService));
}
[HttpGet("description")]
public string GetDescription() => _basicLayoutService.GetLayoutDescription();
}
[ApiController]
[Route("[controller]")]
public sealed class ComplexLayoutController : ControllerBase
{
private readonly ComplexLayoutService _complexLayoutService;
public ComplexLayoutController(ComplexLayoutService complexLayoutService)
{
_complexLayoutService = complexLayoutService ?? throw new ArgumentNullException(nameof(complexLayoutService));
}
[HttpGet("description")]
public string GetDescription() => _complexLayoutService.GetLayoutDescription();
}
This is the most important part. Put this registration code inside the Program.cs class (which is the composition root for an ASP.NET core 6 application):
// Configure named options
builder.Services.Configure<LayoutOptions>(
LayoutOptions.Basic,
builder.Configuration.GetSection($"{LayoutOptions.Layout}:{LayoutOptions.Basic}")
);
builder.Services.Configure<LayoutOptions>(
LayoutOptions.Complex,
builder.Configuration.GetSection($"{LayoutOptions.Layout}:{LayoutOptions.Complex}")
);
// Register the BasicLayoutService by picking the right configuration
builder
.Services
.AddScoped(serviceProvider =>
{
// Get named options
var layoutOptions = serviceProvider.GetRequiredService<IOptionsSnapshot<LayoutOptions>>();
var basicLayoutOptions = layoutOptions.Get(LayoutOptions.Basic);
// Create strongly typed configuration object from named options
var configuration = new LayoutConfiguration(
basicLayoutOptions.Name,
basicLayoutOptions.Color);
// Creates new instance of BasicLayoutService using the service provider and the configuration object
return ActivatorUtilities.CreateInstance<BasicLayoutService>(
serviceProvider,
configuration);
});
// Register the ComplexLayoutService by picking the right configuration
builder
.Services
.AddScoped(serviceProvider =>
{
// Get named options
var layoutOptions = serviceProvider.GetRequiredService<IOptionsSnapshot<LayoutOptions>>();
var complexLayoutOptions = layoutOptions.Get(LayoutOptions.Complex);
// Create strongly typed configuration object from named options
var configuration = new LayoutConfiguration(
complexLayoutOptions.Name,
complexLayoutOptions.Color);
// Creates new instance of ComplexLayoutService using the service provider and the configuration object
return ActivatorUtilities.CreateInstance<ComplexLayoutService>(
serviceProvider,
configuration);
});
You can now test this implementation. As an example, you can set the following configuration in appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Layout": {
"Basic": {
"Name": "Basic Layout",
"Color": "red",
"NumberOfColumns": 2
},
"Complex": {
"Name": "Complex Layout",
"Color": "blue",
"NumberOfColumns": 3
}
}
}
If you run this application and you issue a GET request to /BasicLayout/description, you ge the following response:
Basic layout description. Name: 'Basic Layout' Color: 'red'
If you issue a GET request to /ComplexLayout/description the response you get is:
Complex layout description. Name: 'Complex Layout' Color: 'blue'
A final note on the service lifetime for BasicLayoutService and ComplexLayoutService. In my example I decided to register them as scoped services, because you may want to recompute the configuration object for them (LayoutConfiguration) for each incoming request. This is useful if your configuration may change over time. If this is not the case, you can safely register them as singleton services. That's up to you and depends on your requirements.
I'm trying to test business logic in queries in services. So I don't want my tests to have real access to the database, because they are unit tests, not integration tests.
So I've made a simple example of my context and how I'm trying to shim it.
I have an entity
public class SomeEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
and a service
public class Service
{
public int CountSomeEntites()
{
using (var ctx = new Realcontext())
{
int result = ctx.SomeEntities.Count();
return result;
}
}
}
And this is the real context
public partial class Realcontext : DbContext
{
public virtual DbSet<SomeEntity> SomeEntities { get; set; }
public Realcontext() : base("name=Realcontext")
{
InitializeContext();
}
partial void InitializeContext();
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
So I've tried to create a fake context and I detourned the constructor of the real context in my test method
This is the fake context
public class FakeContext : DbContext
{
public DbSet<SomeEntity> SomeEntities { get; set; }
public FakeContext()
{
}
}
And finally the test class
[TestClass]
public class ServiceTests
{
[TestMethod]
public void CountEmployee_ShoulReturnCorrectResult()
{
using (ShimsContext.Create())
{
ShimRealcontext.Constructor = context => GenerateFakeContext();
ShimDbContext.AllInstances.Dispose = () => DummyDispose();
Service service = new Service();
int result = service.CountSomeEntites();
Assert.AreEqual(result, 2);
}
}
private FakeContext GenerateFakeContext()
{
FakeContext fakeContext = new FakeContext();
fakeContext.SomeEntities.AddRange(new[]
{
new SomeEntity {Id = 1, Name = "entity1"},
new SomeEntity {Id = 2, Name = "entity2"}
});
return fakeContext;
}
}
When I run the test, the RealContext constructor is returned properly, a FakeContext is built in the GenerateFakeContext() method, it contains 2 SomeEntities and it is returned, but right after, in the service, the property SomeEntities of the variable ctx equals to null.
Is it because my variable ctx is declared as a new RealContext()? But calling the constructor of RealContext returns a FakeContext(), so isn't the variable supposed to be of type FakeContext?
Am I doing something wrong? Or is there any other way to test the service without accessing the real database?
I had the simlair situation and I solved it with build configuration and conditional compilation. It's not the best solution, but it worked for me and solved the problem. Here is the receipt:
1. Create DataContext interface
First you need to create an interface which will be implemented by both context classe you going to use. Let it be named just 'IMyDataContext'. Inside it you need to describe all DbSets you need to have access to.
public interaface IMyDataContext
{
DbSet<SomeEntity> SomeEntities { get; set; }
}
And both your context classes need to impelemt it:
public partial class RealDataContext : DataContext, IMyDataContext
{
DbSet<SomeEntity> SomeEntities { get; set; }
/* Contructor, Initialization code, etc... */
}
public class FakeDataContext : DataContext, IMyDataContext
{
DbSet<SomeEntity> SomeEntities { get; set; }
/* Mocking, test doubles, etc... */
}
By the way you can even make properies read-only at interface level.
2. Add 'Test' build configuration
Here you can find how to add new build configuration. I named my configuratin 'Test'. After new configuration is created, go to your DAL project properties, Build section on the left pane. In the 'Configuration' drop-down select the configuration you've just created and in input 'Conditional compilation symbols' type 'TEST'.
3. Incapsulate context injection
To be clear, my approach is still method/property based DI solution =)
So now we need to implement some injection code. For simplicity you can add it right into your service or extract into another class if you need more abstraction. The main idea is to use conditional compilation direcitves instead of IoC framework.
public class Service
{
// Injector method
private IMyDataContext GetContext() {
// Here is the main code
#if TEST // <-- In 'Test' configuration
// we will use fake context
return new FakeDataContext();
#else
// in any other case
// we will use real context
return new RealDataContext();
#endif
}
public int CountSomeEntites()
{
// the service works with interface and does know nothing
// about the implementation
using (IMyDataContext ctx = GetContext())
{
int result = ctx.SomeEntities.Count();
return result;
}
}
}
Limitations
The described approach solves the the problem you described, but it has a limitation: as IoC allows you switch contexts dynamically at runtime, conditional complation requires you to recompile the solution.
In my case it's not a problem - my code isn't covered by tests for 100% and I don't run them on each build. Usually I run tests only before commiting the code, so it's very easy to switch the build configuration in VS, run tests, make sure that nothing was broke and then return to debug mode. In release mode you don't need to run test either. Even if you need - you can craete "Release build test mode" configuration and continue to use the same solution.
Another problem is if you have continuos integration - you need to make additional setup to your build server. Here you have two ways:
Setup two build definitions: one for release and one for tests. If your server is setup to automatic release you need to be careful because test fails will be shown in the second one while the first is deployed.
Set complex build definition which builds your code in Test configuration for the first time, runs test and if they are OK - then recompiles the code in target configuration and prepare to deploy.
Thus, as any solution this one is yet another compromise between simplisity and flexibility.
UPDATE
After some time I understand that the way I described above is very heavy. I mean - build configurations. In case of only two IDataContext implementations: 'Core' and 'Fake' you can simply use bool paramenter and simple if/else branches instead of compilation directives #if/#else/#endif and all the head ache configuring your build server.
If you have more than two implementations - you can use enum and switch block. A probem here is to define what you will return in default case or if value is out of enum's range.
But the main benefit of such approach is that you can be no longer bound to compilation time. Injector parameter could be changed at any time, for example using web.config and ConfigurationManager. Using it you could event switch your data context at run time.
I'm currently trying to work with dependency injection and so far I love. But it's one thing I can't really get my head around and where my current solution just seems wrong.
I'm working with WPF, MVVM and many of the classes I inject need an instance of a project configuration class that isn't initialized until the user create or open a new project in the application.
So my current solution is to have a "ConfigurationHandler" with load/save method and a property that hold an instance of the configuration class after it's loaded. I inject ConfigurationHandler to the others classes and then they can access the configuration after it's loaded. But it seems weird to let classes that never should save/load configuration handle the whole "ConfigurationHandler" and 100% they would just use it to access the configuration instance likt this:
var configuration = configurationHandler.Configuration;
Another problem is that if they try to access the configuration before it's loaded they will get exception (should not really happen as you can't do anything before a project is created/loaded, but still).
But the only other solution I can think of is to use "intialize" methods after a project is created/open but that seems just as bad.
So how do you usually handle cases like this?
Edit: Should add that this configuration class handle information like project path, project name, etc so have nothing to do with the dependency injection itself.
If your configuration is static (read: It's only read during startup of your application, such as from project.json or Web.Config), you can also set it during app startup/the composition root.
The new ASP.NET 5 uses it heavily and it works very well. Basically you will have an IConfiguration<T> interface and a POCO class, which you set up during the app startup and can resolve/inject it into your services.
public interface IConfiguration<T> where T : class
{
T Configuration { get; }
}
And it's default implementation
public interface DefaultConfiguration<T> where T : class
{
private readonly T configuration;
public T Configuration {
return configuration;
}
public DefaultConfiguration<T>(T config)
{
this.configuration = this.configuration;
}
}
And your POCO class
public class AppConfiguration
{
public string OneOption { get; set; }
public string OtherOption { get; set; }
}
In your composition root, you would then register it, like
// read Web.Config
Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
container.AddSingleton<IConfiguration<AppConfiguration>>(new DefaultConfiguration<AppConfiguration>(
new AppConfiguration
{
OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
And finally, all you have to declare in your services is
public class MyService : IMyService
{
public MyService(IUserRepository, IConfiguration<AppConfiguration> appConfig)
{
...
if(appConfig.OneOption=="someValue") {
// do something
};
}
}
Finally you can make this a bit easier to configure, if you write an extension method like
public static class MyContainerExtension
{
public static void Configure<T>(this IMyContainer container, Action<T> config) where T : class, new()
{
var t = new T();
config(t);
container.AddSingelton<IConfiguration<T>>(t);
}
}
Then all you need to do is
container.Configure<AppConfiguration>(
config =>
{
config.OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
config.OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
to set it up
Instead of Constructor Injection, consider using an Ambient Context approach.
The last type of DI we’ll discuss is making dependencies available
through a static accessor. It is also called injection through the
ambient context. It is used when implementing cross-cutting concerns.
This is a good option if the classes that need access to your configuration are of different types in different layers or libraries - i.e. is a true cross-cutting concern.
(Quote source)
Example, based on the classic Time Provider one from [Dependency Injection in .NET][2]
abstract class CustomConfiguration
{
//current dependency stored in static field
private static CustomConfiguration current;
//static property which gives access to dependency
public static CustomConfiguration Current
{
get
{
if (current == null)
{
//Ambient Context can't return null, so we assign a Local Default
current = new DefaultCustomConfiguration();
}
return current;
}
set
{
//allows to set different implementation of abstraction than Local Default
current = (value == null) ? new DefaultCustomConfiguration() : value;
}
}
//service which should be override by subclass
public virtual string SomeSetting { get; }
}
//Local Default
class DefaultCustomConfiguration : CustomConfiguration
{
public override string SomeSetting
{
get { return "setting"; }
}
}
Usage
CustomConfiguration.Current.SomeSetting;
There are other DI Patterns that could be used, but require changes to the class that need it. If Configuration is a cross cutting concern Ambient Context could be the best fit.
Constructor Injection Example
public SomeClass(IConfiguration config)
{
}
Property Injection
public SomeClass()
{
IConfiguration configuration { get; set; }
}
Method Injection
public SomeClass()
{
public void DoSomethingNeedingConfiguation(IConfiguration config)
{
}
}
There is also Service Locator, but Service Locator is (IMO) an anti-pattern.
There are several questions on Stack Overflow that are similar but not exactly what I'm looking for. I would like to do Ninject binding based on a runtime condition, that isn't pre-known on startup. The other questions on Stack Overflow for dynamic binding revolve around binding based on a config file or some such - I need to it to happen conditionally based on a database value while processing the data for a particular entity. E.g.,
public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}
public interface IExport
{
void ExportData(DataTable data);
}
Elsewhere, I have 2 dlls that implement IExport
public PartnerAExport : IExport
{
private readonly _db;
public PartnerAExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter A's data...
}
}
Then for partner B;
public PartnerBExport : IExport
{
private readonly _db;
public PartnerBExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter B's data...
}
}
Current Ninject binding is;
public class NinjectWebBindingsModule : NinjectModule
{
public override void Load()
{
Bind<PADBEntities>().ToSelf();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
}
}
So how do I set up the bindings such that I can do;
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = ninject.Resolve<IExport>(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
Is this possible? It seems like it should be but I can't quite figure how to go about it. The existing binding configuration above works fine for static bindings but I need something I can resolve at runtime. Is the above possible or am I just going to have to bypass Ninject and load the plugins using old-school reflection? If so, how can I use that method to resolve any constructor arguments via Ninject as with the statically bound objects?
UPDATE: I've updated my code with BatteryBackupUnit's solution such that I now have the following;
Bind<PADBEntities>().ToSelf().InRequestScope();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
.Configure(c => c.InRequestScope())
);
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.Modules.*.dll")
.SelectAllClasses()
.InheritedFrom<IExportService>()
.BindSelection((type, baseTypes) => new[] { typeof(IExportService) })
);
Kernel.Bind<IExportServiceDictionary>().To<ExportServiceDictionary>().InSingletonScope();
ExportServiceDictionary dictionary = KernelInstance.Get<ExportServiceDictionary>();
Instantiating the export implementations within 2 test modules works and instantiates the PADBEntites context just fine. However, all other bindings in my services layer now no longer work for the rest of the system. Likewise, I cannot bind the export layer if I change PADBEntities variable/ctor argument to an ISomeEntityService component. It seems I'm missing one last step in configuring the bindings to get this work. Any thoughts?
Error: "Error activating ISomeEntityService. No matching bindings are available and the type is not self-bindable"
Update 2: Eventually got this working with a bit of trial and error using BatteryBackupUnit's solution though I'm not too happy with the hoops to jump thought. Any other more concise solution is welcome.
I changed the original convention binding of;
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
to the much more verbose and explicit;
Bind<IActionService>().To<ActionService>().InRequestScope();
Bind<IAuditedActionService>().To<AuditedActionService>().InRequestScope();
Bind<ICallService>().To<CallService>().InRequestScope();
Bind<ICompanyService>().To<CompanyService>().InRequestScope();
//...and so on for 30+ lines
Not my favorite solution but it works with explicit and convention based binding but not with two conventions. Can anyone see where I'm going wrong with the binding?
Update 3: Disregard the issue with the bindings in Update 2. It appears that I've found a bug in Ninject relating to having multiple binding modules in a referenced library. A change in module A, even though never hit via breakpoint will break a project explicitly using a different module B. Go figure.
It's important to note that while the actual "condition match" is a runtime condition, you actually know the possible set of matches in advance (at least on startup when building the container) - which is evidenced by the use of the conventions. This is what the conditional / contextual bindings are about (described in the Ninject WIKI and covered in several questions). So you actually don't need to do the binding at an arbitrary runtime-time, rather you just have to do the resolution/selection at an arbitrary time (resolution can actually be done in advance => fail early).
Here's a possible solution, which features:
creation of all bindings on startup
fail early: verification of bindings on startup (through instanciation of all bound IExports)
selection of IExport at an arbitrary runtime
.
internal interface IExportDictionary
{
IExport Get(string key);
}
internal class ExportDictionary : IExportDictionary
{
private readonly Dictionary<string, IExport> dictionary;
public ExportDictionary(IEnumerable<IExport> exports)
{
dictionary = new Dictionary<string, IExport>();
foreach (IExport export in exports)
{
dictionary.Add(export.GetType().Assembly.FullName, export);
}
}
public IExport Get(string key)
{
return dictionary[key];
}
}
Composition root:
// this is just going to bind the IExports.
// If other types need to be bound, go ahead and adapt this or add other bindings.
kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.InheritedFrom<IExport>()
.BindSelection((type, baseTypes) => new[] { typeof(IExport) }));
kernel.Bind<IExportDictionary>().To<ExportDictionary>().InSingletonScope();
// create the dictionary immediately after the kernel is initialized.
// do this in the "composition root".
// why? creation of the dictionary will lead to creation of all `IExport`
// that means if one cannot be created because a binding is missing (or such)
// it will fail here (=> fail early).
var exportDictionary = kernel.Get<IExportDictionary>();
Now IExportDictionary can be injected into any component and just used like "required":
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = exportDictionary.Get(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
I would like to do Ninject binding based on a runtime condition, that isn't pre-known on startup.
Prevent making runtime decisions during building of the object graphs. This complicates your configuration and makes your configuration hard to verify. Ideally, your object graphs should be fixed and should not change shape at runtime.
Instead, make the runtime decision at... runtime, by moving this into a proxy class for IExport. How such proxy exactly looks like, depends on your exact situation, but here's an example:
public sealed class ExportProxy : IExport
{
private readonly IExport export1;
private readonly IExport export2;
public ExportProxy(IExport export1, IExport export2) {
this.export1 = export1;
this.export2 = export2;
}
void IExport.ExportData(Partner partner) {
IExport exportModule = GetExportModule(partner.ExportImplementationAssembly);
exportModule.ExportData(partner);
}
private IExport GetExportModule(ImplementationAssembly assembly) {
if (assembly.Name = "A") return this.export1;
if (assembly.Name = "B") return this.export2;
throw new InvalidOperationException(assembly.Name);
}
}
Or perhaps you're dealing with a set of dynamically determined assemblies. In that case you can supply the proxy with a export provider delegate. For instance:
public sealed class ExportProxy : IExport
{
private readonly Func<ImplementationAssembly, IExport> exportProvider;
public ExportProxy(Func<ImplementationAssembly, IExport> exportProvider) {
this.exportProvider = exportProvider;
}
void IExport.ExportData(Partner partner) {
IExport exportModule = this.exportProvider(partner.ExportImplementationAssembly);
exportModule.ExportData(partner);
}
}
By supplying the proxy with a Func<,> you can still make the decision at the place where you register your ExportProxy (the composition root) where you can query the system for assemblies. This way you can register the IExport implementations up front in the container, which improves verifiability of the configuration. If you registered all IExport implementations using a key, you can do the following simple registration for the ExportProxy
kernel.Bind<IExport>().ToInstance(new ExportProxy(
assembly => kernel.Get<IExport>(assembly.Name)));
In my MVC application I defined two interfaces: IQueryMappingsConfigurator and ICommandMappingsConfigurator. Those two interfaces are used for supplying EntityFramework mappings for query and command contexts.
In the same solution I have two services: IMembershipService and IMessagingService; for each of those services there is a Registry specifying implementations for ICommandMappingsConfigurator and IQueryMappingsConfigurator:
// In Services.Membership project
public class MembershipRegistry : Registry
{
public MembershipRegistry()
{
For<ICommandMappingsConfigurator>()
.Use<MembershipCommandMappingsConfigurator>();
For<IQueryMappingsConfigurator>()
.Use<MembershipQueryMappingsConfigurator>();
For<IMembershipService>()
.Use<MembershipService>();
}
}
// In Services.Messaging project
public class MessagingRegistry : Registry
{
public MessagingRegistry()
{
For<ICommandMappingsConfigurator>()
.Use<MessagingCommandMappingsConfigurator>();
For<IQueryMappingsConfigurator>()
.Use<MessagingQueryMappingsConfigurator>();
For<IMessagingService>()
.Use<MessagingService>();
}
}
Each service has a dependency on both IQueryMappingsConfigurator and ICommandMappingsConfigurator.
IMembershipService and IMessagingService are used by controllers in the MVC project:
public class MessageController : Controller
{
public MessageController(IMessagingService service){ }
}
public class MembershipController : Controller
{
public MembershipController(IMembershipService service){}
}
How can I configure the StructureMap container so that when a dependency for IMessagingService is required it will load the proper implementation for ICommandMappingsConfigurator and IQueryMappingsConfigurator?
I've tried using a custom registration convention like this:
public class ServiceRegistrationConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (IsApplicationService(type))
{
registry.Scan(_ =>
{
_.AssemblyContainingType(type);
_.LookForRegistries();
});
}
}
}
However, when I try accessing an action method from MessageController I get the error
There is no configuration specified for IMessagingService
When I debug the application I can see the Process method being hit with the type of IMessagingService.
The correct way to compose your application is to make a composition root. If you indeed have one (which isn't clear from your question), this step is done only 1 time per application start so there is no way to change the DI configuration's state during runtime (or at least you should assume there is not). It doesn't matter if the dependencies are in different application layers, they will overlap if they use the same interface.
Before you change your DI configuration, you should check whether you are violating the Liskov Substitution Principle. Unless you really need the ability to swap the MembershipCommandMappingsConfigurator and MessagingCommandMappingsConfigurator in your application, a simple solution is just to give each a different interface (in this case IMembershipCommandMappingsConfigurator and IMessagingCommandMappingsConfigurator).
If you are not violating the LSP, one option is to use generics to disambiguate the dependency chain.
public class MyRegistry : Registry
{
public MyRegistry()
{
For(typeof(ICommandMappingsConfigurator<>))
.Use(typeof(CommandMappingsConfigurator<>));
For(typeof(IQueryMappingsConfigurator<>)
.Use(typeof(QueryMappingsConfigurator<>));
For<IMessagingService>()
.Use<MessagingService>();
For<IMembershipService>()
.Use<MembershipService>();
}
}
public class CommandMappingsConfigurator<MessagingService> : ICommandMappingsConfigurator<MessagingService>
{
// ...
}
public class QueryMappingsConfigurator<MessagingService> : IQueryMappingsConfigurator<MessagingService>
{
// ...
}
public class MessagingService
{
public MessagingService(
ICommandMappingsConfigurator<MessagingService> commandMappingsConfigurator,
IQueryMappingsConfigurator<MessagingService> queryMappingsConfigurator)
{
// ...
}
}
public class CommandMappingsConfigurator<MembershipService> : ICommandMappingsConfigurator<MembershipService>
{
// ...
}
public class QueryMappingsConfigurator<MembershipService> : IQueryMappingsConfigurator<MembershipService>
{
// ...
}
public class MembershipService
{
public MembershipService(
ICommandMappingsConfigurator<MembershipService> commandMappingsConfigurator,
IQueryMappingsConfigurator<MembershipService> queryMappingsConfigurator)
{
// ...
}
}
Another option - in StructureMap you can used smart instances in the configuration to specify exactly what instance goes where, so at runtime you can have different implementations of the same interface.
public class MembershipRegistry : Registry
{
public MembershipRegistry()
{
var commandMappingsConfigurator = For<ICommandMappingsConfigurator>()
.Use<MembershipCommandMappingsConfigurator>();
var queryMappingsConfigurator = For<IQueryMappingsConfigurator>()
.Use<MembershipQueryMappingsConfigurator>();
For<IMembershipService>()
.Use<MembershipService>()
.Ctor<ICommandMappingsConfigurator>().Is(commandMappingsConfigurator)
.Ctor<IQueryMappingsConfigurator>().Is(queryMappingsConfigurator);
}
}
public class MessagingRegistry : Registry
{
public MessagingRegistry()
{
var commandMappingsConfigurator = For<ICommandMappingsConfigurator>()
.Use<MessagingCommandMappingsConfigurator>();
var queryMappingsConfigurator = For<IQueryMappingsConfigurator>()
.Use<MessagingQueryMappingsConfigurator>();
For<IMessagingService>()
.Use<MessagingService>();
.Ctor<ICommandMappingsConfigurator>().Is(commandMappingsConfigurator)
.Ctor<IQueryMappingsConfigurator>().Is(queryMappingsConfigurator);
}
}
You can also use named instances, but smart instances have compile-time type checking support which makes them easier to configure.
There is no reason to use .Scan (which uses Reflection) to configure the registries, unless your application has some kind of plugin architecture. For a normal application with multiple layers, you can configure them explicitly.
var container = new Container();
container.Configure(r => r.AddRegistry<MembershipRegistry>());
container.Configure(r => r.AddRegistry<MessagingRegistry>());