I have the following interfaces and classes:
public interface ILoggingService { ... }
public class LoggingService {
public LoggingService(ILoggingRepository loggingRepository) { ... }
...
}
public interface ILoggingRepository { ... }
public class DatabaseLoggingRepository {
public DatabaseLoggingRepository(string ConnectionString) { ... }
...
}
public class FileLoggingRepository {
public FileLoggingRepository(string LogFilePath) { ... }
...
}
I'm refactoring my software to use Unity IoC framework and am looking for a way to pass the specific configuration to each ILoggingRepository implementation.
I think that the best way would be to change DatabaseLoggingRepository's and FileLoggingRepository's constructors to have no parameters at all and have them configured by some configuration file. However, because of my acceptance tests I would need a easy way to override these settings while running my tests.
Am I on the right track and if I am, which configuration files should I use? Alternative ways are welcome as well.
What we've decided to do is create a class, in your case it would be LoggingConfiguration, and have that passed to the constructo of the repository. If you resolve using Unity it will instantiate this class using Activator, wuthout having to register it. In your tests however, you just greate a new instance of a derived configuration class, providing different values.
Does it makes sense? Should I clarify more?
Update: I've decided to provide some additional clarification. So, you already have two implementations, and now you want each configuration to query for its proper configuration setting.
I would extend the ILoggingRepository's constructor to look like this:
public ILoggingRepository(ILoggingConfigurationProvider confProvider);
You can then create one implementation for your normal operation which has two properties:
public LoggingConfigurationProvider : ILoggingConfigurationProvider {
public LoggingConfigurationProvider() {
// load both values from configuration file
}
public string LogPath { get; set; }
public string ConnectionString { get; set; }
}
When you instantiate your class via normal IoC operation this will get resolved by the container and you'll configuration options will get loaded from the conf file. When you however want to do Unit tests you:
1) Create a new "Mock" implementation
public class MockLoggingConfigurationProvider : ILoggingConfigurationProvider {
public MockLoggingConfigurationProvider() {
// set both values to a test value
}
public string LogPath { get; set; }
public string ConnectionString { get; set; }
}
Now you can either create the repository using a constructor:
new LoggingRepository(new MockLoggingConfigurationProvider());
or if you want the whole IoC mechanism to be used, you simply (when setting up the container) register this implementation of the interface. Because the unit tests are separate, you don't share the registrations right? So that should give you what you need, the ability to change this settings depending on weather they are being executed as a unit test or not.
In real life, I wouldn't even bother with this, and just create a mock logging repository and have it write somewhere else. Unless you want to test the repository to a test database/file. In which case I'd do as specified.
Hope it helps.
As a design suggestion does not force IoC to deal with configuration stuff. Each logger should manage the configuration the way they prefer in its implementation. IoC should just inject the logger. For the unit/integration test, in both case you should e able to provide a configuration for the logger, for example using log4net I'm used to configure the logging subsystem in the Startup of the test by the api, and I create an appender that write just everithing on the console. You can't Insolate configuration by IoC since each possible logging system does not necessary share a contract for the Configuration part.
Related
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.
I'm currently playing around with the IoC concept (with a WPF app) and I haven't decided on the tool I'll used with it just yet as I'm still trying to get the grasp of it but I'm confused as to how this would be configured regarding the specific parameters each component.
I understand how you define the relevant library in the config file and how it will determine which one should be used by the app and what its lifespan should be but what about each library requiring its own specific set of parameters.
Where do you get these from and when do you pass them on?
Taking your typical logger for example.
I have the following interface:
public interface ILogger
{
void Write(string message);
}
I have the logger class itself:
public class Logger : ILogger
{
private readonly ILogger _logger;
public Logger (ILogger logger)
{
_logger = logger;
}
public void Write(string message)
{
_logger.Write(message);
}
}
I then define multiple loggers each requiring their own parameter, so I implemented the following:
a) database logger: where a connection string is required so that I can log my message to a database.
public void LoggerDb: ILogger
{
public void Write(string message)
{
}
public ConnectionString {get; set;}
}
b) file logger: where a filename is required so that I can log my message to the relevant log file.
public void LoggerFile: ILogger
{
public void Write(string message)
{
}
public Filename {get; set;}
}
c) console logger: where no parameter is required as I just want to output my message to a console window.
public void LoggerConsole: ILogger
{
public void Write(string message)
{
}
}
In my console test app, I've got the following code in the Program.cs:
static void Main(string[] args)
{
string logTypeId = "d";
ILogger logType;
if (logTypeId == "d")
{
logType = new LoggerDb("Data Source=....");
}
else if (logTypeId == "f"
{
logType = new LoggerFile("c:\\mylog.txt");
}
else
{
logType = new LoggerConsole();
}
Logger logger = new Logger(logType);
logger.Write("Message 1");
logger.Write("Message 2");
logger.Write("Message 3");
}
I understand this is not how the code would be if I used an IoC tool. I'm just trying to highlight what I'm trying to achieve and I'm trying to get answers to the following questions:
Can this be achieved using an IoC tool i.e. pass specific parameter depending on the logger type that's used/defined in the IoC section of the app.config?
Is this the correct approach i.e. Having specific loggers with their own constructors parameters? If not, can you explain why and what should be the correct approach. I don't mind the IoC tool you use. I just want to understand how this should be done.
Where should these additional parameters be stored in the app.config?
First, note that in order to implement DI via an IoC, it is by no means required to configure your container in a configuration file (although it's certainly an option and many containers support it).
Most IoC containers these days also allow you to specify your setup in code. So I guess the answer is: it really depends on the IoC container you plan to use. My opinion: avoid xml-based configuration if you can; it's often a pain to maintain and brings little value if you ask me. In your code-based configuration you can still refer to configuration parameters from app.config or other.
You can also turn the question around: is it a requirement to have the container configuration in a separate file (and why)? If yes, look for a container that supports this well. But most do.
Some examples of configuration using a code-based DSL:
Autofac modules: http://docs.autofac.org/en/latest/configuration/modules.html
StructureMap: http://structuremap.github.io/registration/registry-dsl/
Some examples of xml configuration:
Autofac: http://docs.autofac.org/en/latest/configuration/xml.html
Spring.NET container: http://www.springframework.net/doc-latest/reference/html/objects.html
structuremap: http://docs.structuremap.net/configuring-structuremap/structuremap-xml-configuration/
It depends ;)
I can't speak for all DependencyInjection Tools, but many of them should support this functionality.
I don't see anything that speak against this. If you want to call different Loggers explicitly, you can do this. But you can also use some kind of LogListeners. One for DB, one for File and so on. And your Logger just delegates the LogMessage to all Loggers. But this depends on what you want or need ;)
This also depends on the implementation of the Logger. It's common to store the ConnectionString in the config. The other parameters are too specific, but you you can store them in config, too.
How can I inject different implementation of object for a specific class?
For example, in Unity, I can define two implementations of IRepository
container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository");
container.RegisterType<IRepository, BaseRepository>();
and call the needed implementation
public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository)
As #Tseng pointed, there is no built-in solution for named binding. However using factory method may be helpful for your case. Example should be something like below:
Create a repository resolver:
public interface IRepositoryResolver
{
IRepository GetRepositoryByName(string name);
}
public class RepositoryResolver : IRepositoryResolver
{
private readonly IServiceProvider _serviceProvider;
public RepositoryResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IRepository GetRepositoryByName(string name)
{
if(name == "TestSuiteRepository")
return _serviceProvider.GetService<TestSuiteRepositor>();
//... other condition
else
return _serviceProvider.GetService<BaseRepositor>();
}
}
Register needed services in ConfigureServices.cs
services.AddSingleton<IRepositoryResolver, RepositoryResolver>();
services.AddTransient<TestSuiteRepository>();
services.AddTransient<BaseRepository>();
Finally use it in any class:
public class BaselineManager
{
private readonly IRepository _repository;
public BaselineManager(IRepositoryResolver repositoryResolver)
{
_repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");
}
}
In addition to #adem-caglin answer I'd like to post here some reusable code I've created for name-based registrations.
UPDATE Now it's available as nuget package.
In order to register your services you'll need to add following code to your Startup class:
services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();
services.AddByName<IService>()
.Add<ServiceA>("key1")
.Add<ServiceB>("key2")
.Add<ServiceC>("key3")
.Build();
Then you can use it via IServiceByNameFactory interface:
public AccountController(IServiceByNameFactory<IService> factory) {
_service = factory.GetByName("key2");
}
Or you can use factory registration to keep the client code clean (which I prefer)
_container.AddScoped<AccountController>(s => new AccountController(s.GetByName<IService>("key2")));
Full code of the extension is in github.
You can't with the built-in ASP.NET Core IoC container.
This is by design. The built-in container is intentionally kept simple and easily extensible, so you can plug third-party containers in if you need more features.
You have to use a third-party container to do this, like Autofac (see docs).
public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository)
After having read the official documentation for dependency injection, I don't think you can do it in this way.
But the question I have is: do you need these two implementations at the same time? Because if you don't, you can create multiple environments through environment variables and have specific functionality in the Startup class based on the current environment, or even create multiple Startup{EnvironmentName} classes.
When an ASP.NET Core application starts, the Startup class is used to bootstrap the application, load its configuration settings, etc. (learn more about ASP.NET startup). However, if a class exists named Startup{EnvironmentName} (for example StartupDevelopment), and the ASPNETCORE_ENVIRONMENT environment variable matches that name, then that Startup class is used instead. Thus, you could configure Startup for development, but have a separate StartupProduction that would be used when the app is run in production. Or vice versa.
I also wrote an article about injecting dependencies from a JSON file so you don't have to recompile the entire application every time you want to switch between implementations. Basically, you keep a JSON array with services like this:
"services": [
{
"serviceType": "ITest",
"implementationType": "Test",
"lifetime": "Transient"
}
]
Then you can modify the desired implementation in this file and not have to recompile or change environment variables.
Hope this helps!
First up, this is probably still a bad idea. What you're trying to achieve is a separation between how the dependencies are used and how they are defined. But you want to work with the dependency injection framework, instead of against it. Avoiding the poor discover-ability of the service locator anti-pattern. Why not use generics in a similar way to ILogger<T> / IOptions<T>?
public BaselineManager(RepositoryMapping<BaselineManager> repository){
_repository = repository.Repository;
}
public class RepositoryMapping<T>{
private IServiceProvider _provider;
private Type _implementationType;
public RepositoryMapping(IServiceProvider provider, Type implementationType){
_provider = provider;
_implementationType = implementationType;
}
public IRepository Repository => (IRepository)_provider.GetService(_implementationType);
}
public static IServiceCollection MapRepository<T,R>(this IServiceCollection services) where R : IRepository =>
services.AddTransient(p => new RepositoryMapping<T>(p, typeof(R)));
services.AddScoped<BaselineManager>();
services.MapRepository<BaselineManager, BaseRepository>();
Since .net core 3, a validation error should be raised if you have failed to define a mapping.
I am working on an app which uses active directory to retrieve users. Sometimes I need to work on the app but AD is not available. I use a wrapper class to retrieve the AD user. I would like to inject a different class based on the configuration. I was thinking on using an appSetting that would tell me the current configutarion and decide what type to use when injecting. Is it possible to get the current configuration without using a Web.config transform? Is it possible to inject objects using Unity based on Web.config transformations? Can you recommend a better approach?
[UPDATE]
I have a user repository class that loads the users from AD. All I need is to be able to change the implementation of this repository class so that when AD is unavailable I can load the users a different way. This would only be used for development, production would always access AD and retrieve users.
You can use preprocessor directives:
#if DEBUG
// register fake repository
#else
// register AD repository
#endif
Well, Dependency Injection is incredibly powerful, agile, and creates a separation of concerns. The pitfall in your approach will come from validation. You see, with this approach you have to choose a concrete implementation.
So how will you call those two classes?
public class LogToText : ILogger
{
public void LogMessage(string message) { }
}
public class LogToEvent : ILogger
{
public void LogMessage(string message) { }
}
You have these two implementations, but when you pass the interface to:
public class AD
{
public AD(ILogger logger) { }
}
So the question will be do you feel that you can properly validate to choose the proper implementation effectively. Otherwise, Dependency Injection may not work well. We don't entirely know the usage or goal, so our advice may not be truly beneficial. Hopefully you see what I mean, because you'll have to see if you can't test a particular way.
You could use an Abstraction for this:
public interface IPersonService
{
IEnumerable<Person> Find(PersonSearchParameters searchParams);
Person GetByAccountName(string accountName);
[ETC...]
}
Then both your AD and Development implements this interface.
To make things easier, I suggest using StructureMap IoC, so you can easily do this:
x.For<IPersonService>.Use<ActiveDirectoryPersonService>(); //for production
or
x.For<IPersonService>.Use<MockPersonService>(); //for development
When using this you can, for instancce:
public class TestController : Controller
{
IPersonService _service;
public TestController(IPersonService service)
{
_service = service;
}
}
Instead of using an XML file for configuration in this case, I suggest using the Fluent code of Structure Map, it's better when refactoring and to avoid mistyping because it compiles.
StructureMap:
http://structuremap.net
Easy Installable via NuGET
A different approach would be to use the build configuration, read back from the assembly.
var buildConfiguration = typeof(Program).Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>()?.Configuration;
if (buildConfiguration == "Debug")
{
// register fake repository
}
else
{
// register AD repository
}
Then it is safer to apply refactorings or automatic code clean up (e.g. ReSharper etc.). Depending on your current configuration, code cleanup can otherwise remove unused usings. What then leads to build issues if an other configuration is used.
I'm currently developing a plugin to use in any application, and the configuration of the plugin is done through the usage of either a web.config or an app.config file.
Now, I want to unit test my plugin. I want to test the different behaviour in various conditions:
For exmaple:
Only 1 single item should be marked as 'default'.
A collection of providers can be registered in the plugin, however the name must be unique, otherwise, a specific exception is thrown.
My question:
I have a unit test project and I want to test each method with another application configuration file, is this possible?
I've tried reading the file from ExeConfiguration, but I don't get it to work.
Thanks for the feedback.
Kr,
This is what we do (same as #THG) explained in his answer.
public interface IConfiguration
{
string SettingA { get; }
string SettingB { get; }
}
public class Configuration : IConfiguration
{
public string SettingA
{
get
{
return ConfigurationManager.AppSettings["SettingA"];
}
}
public string SettingB
{
get
{
return ConfigurationManager.AppSettings["SettingB"];
}
}
}
Then in your test
var config = MockRepository.GenerateStub<IConfiguration>();
config.Stub(x => x.SettingA).Return("Fred");
My recommendation is to mock the integration with the config file instead of using it directly. This approach offers much more flexibility and removes the need to worry about multiple config files.
You can either use a mocking framework or create you own layer of abstraction on top of the code that fetches the config values.