I am writing a plugin as part of a plugin architecture. The way plugins are created is via reflection and CreateInstance. Therefore the default constructor is called. This code I cannot touch and I am trying to find a sensible way to use DI without the ability to use a framework.
I believe I have 3 options:
i) Poor Man's DI (PMDI)
ii) Factory Pattern
iii) TinyIOC or similar (one cs file that handles DI)
I started looking at PMDI but then a dependency needed another dependency so I ended up with something similar to this which is ugly and could get worse:
public MyMainPluginClass() : this(new Repo(new Logger()))
{
}
public MyMainPluginClass(IRepo repo)
{
}
I then moved onto the idea of a Factory Pattern but could not find any decent demo code. I assume I would have something like this:
public static FactoryUtility
{
public static IRepo GetRepo()
{
return new Repo(GetLogger());
}
public static ILogger GetLogger()
{
return new Logger();
}
}
public MyMainPluginClass() : this(FactoryUtility.GetRepo())
{
}
public MyMainPluginClass(IRepo repo)
{
}
Is that how it would look?
I then came across TinyIOC which is one class that does all the dependency registering but I believe it requires to be setup in a Program.cs which I don't have in a class library. If someone has any experience using this could it be used like so:
public MyMainPluginClass()
{
var container = TinyIoCContainer.Current;
container.AutoRegister();
var implementation = container.Resolve<IRepo>();
MyMainPluginClass(implementation);
}
public MyMainPluginClass(IRepo repo)
{
}
Are there any alternative approaches to achieve DI without using a 3rd party library and if not which approach would choose from above?
NOTE: The code above has not been compiled and is just an idea of what I think would work. Please post corrections if they are valid approaches.
Since you're using .NET 4, you might want to consider using MEF, as it's built into the framework itself. This looks like fairly straightforward DI, which MEF handles well, as it's intended mainly for extensibility.
For details, see the Learn More page on the MEF CodePlex site.
I went with TinyIOC in the end. Unfortunately the plugin's constructor gets called several times before its actually up and running. I simply set a boolean to prevent registration being called several times and therefore it allows me to simply auto-register dependencies and off we go.
public MyMainPluginClass() : this(FactoryUtility.SetupIOC())
{
}
public MyMainPluginClass(IRepo repo)
{
}
public static class FactoryUtility
{
private static bool Initialized = false;
public static IRepo SetupIOC()
{
var container = TinyIoCContainer.Current;
if (!Initialized)
{
container.AutoRegister(new[] { Assembly.GetExecutingAssembly() });
Initialized = true;
}
var result = container.Resolve<IRepo>();
return result;
}
}
If I absolutely don't want to add a dependency to a DI container, I like to use my own TinyIOC (sorry about the name, didn't know it was taken), which for small projects gives me the same semantics as using a container, but clocks in at below 200 LOC.
If you are interested, here is the code: https://gist.github.com/ad7608e2ae10b0f04229
Related
I am looking for simple approaches to the use of the Options pattern for mixes of environment-agnostic, environment-specific and secret configuration in .NET Core. I have seen unnecessarily complex approaches to this, and developed one approach which feels much simpler than what I have seen, but still begs to be simplified further. I will provide that in the first answer to this question.
So, put as a clear question:
What is the simplest approach to Binding Options objects to Configuration sections in .NET Core that is a consistent approach across all types of .NET Core projects, e.g. Function apps, Worker services, ASP.NET Core, etc?
Bonus questions:
How can this approach be used without requiring the use of a Dependency Injection container?
creating an instance of IConfiguration with a Dependency Injection container feels very messy to me in that IConfiguration then needs to be a parameter of every constructor within a chain of dependencies, or it requires that all class/interface implementations need to be registered within the DI container.
How can this approach be used with a Dependency Injection container?
most people I've met do use DI containers (either Autofac or the .NET Core DI container) so it's definitely worth discussing how the approach might also be useful in a DI container scenario.
===========
It's worth noting that I completely adhere to the Dependency Inversion principle via Dependency Injection, but do so via chained constructors (typically two) and only minimally use DI containers in .NET Core - almost always for logging only. There are a number of reasons for this which are probably best stated by Ygor Bugayenko in Elegant Objects and not the topic of this post.
===========
One more thing:
I am not going to accept my own answer that I'm providing below. In fact, I'm not going to accept an answer for awhile so that there is plenty of time for alternate approaches to be provided in the answers.
Looking forward to your ideas! Cheers
One approach to this is to create Options objects that lazy-initialize, and use an implementation of IConfiguration that has been stored in a singleton at startup that is available to the entire application in order to eliminate the need for DI container gymnastics. I believe that the following approach does not diverge from Microsoft's intent regarding the use of the Options pattern, but is a different and IMO simpler approach to doing so.
In this example implementation I'm going to use naive Singleton patterns for simplicity - if you're concerned at all with multiple threads creating multiple instances you might go with the use of the Lazy class or a traditional double-locking singleton pattern.
I'll use a RemoteCache configuration object as an example of an Options compliant model:
public class RemoteCache
{
private const string SectionName = "Redis";
private static RemoteCache _instance;
private static readonly Redis RedisConfig = new();
public static RemoteCache Instance()
{
if (_instance is not null) return _instance;
_instance = new RemoteCache();
return _instance;
}
private RemoteCache() { }
public string CacheConnection => RedisConfigInstance.CacheConnection;
public string CacheKey => RedisConfigInstance.CacheKey;
private Redis RedisConfigInstance
{
get
{
if (string.IsNullOrWhiteSpace(RedisConfig.CacheConnection) is false) return RedisConfig;
AppConfiguration.Instance.GetSection(SectionName).Bind(RedisConfig);
return RedisConfig;
}
}
private class Redis
{
public string CacheConnection { get; set; } = string.Empty;
public string CacheKey { get; set; } = string.Empty;
}
}
Q. What is AppConfiguration and where does this get initialized?
A. A static class that gets initialized in your Startup class.
My Startup class for a function app typically looks like this. You might notice that I am using "appsettings.json" which is typically not done in function apps, but I wanted the environment-agnostic portion of my configuration to follow the same pattern used in non-function-apps, rather than shoving dang-near everything into Environment Variables which seems pretty typical of function apps and leads to a glut of environment variables being pushed in during the deployment process. I do use environment variables for secrets in non-local deployments, and use KeyVault references to acquire those secrets at runtime. When running locally, secrets are acquired using the UserSecrets.
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.SetBasePath(executionContextOptions.AppDirectory)
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json", false)
.AddJsonFile("local.settings.json", true)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true);
AppConfiguration.Instance = configurationBuilder.Build();
builder.Services.AddLogging(logging =>
{
logging.AddApplicationInsights(new ApplicationInsightsConfiguration().AppInsightsInstrumentationKey());
}
}
}
This is all the AppConfiguration class is:
public static class AppConfiguration
{
public static IConfiguration Instance;
}
So, once you have your startup code and AppConfiguration class in place you can happily create Options model objects that map to your configuration sections to your heart's content. These models are implemented as singletons so you can then access them from whatever code needs configuration no matter how deeply nested in your application.
Usage example:
(I prefer accessing configuration models through an interface, which allows my code to be TDD with true unit tests that use fakes of config implementations [of course, use mocks if you prefer])
public interface IRemoteCacheConfiguration
{
string CacheConnection();
string RedisCacheKey();
}
public class RemoteCacheConfiguration : IRemoteCacheConfiguration
{
public string CacheConnection() => RemoteCache.Instance().CacheConnection;
public string RedisCacheKey() => RemoteCache.Instance().CacheKey;
}
public class MyThingThatAccessesTheCache
{
private readonly IRemoteCacheConfiguration _remoteCacheConfiguration;
public MyThingThatAccessesTheCache() : this(new RemoteCacheConfiguration()) { }
public MyThingThatAccessesTheCache(IRemoteCacheConfiguration remoteCacheConfiguration) => _remoteCacheConfiguration = remoteCacheConfiguration;
public void DoStuff()
{
string cacheConnection = _remoteCacheConfiguration.CacheConnection();
}
}
Until now, I have used the Unity IOC container to resolve dependencies, which works just fine. With the Unity DI, I normally resolve instances in the following way:
Public class TestClass {
public TestClass()
{
var instance = IOC.resolve<InterfaceClassToResolve>();
}
}
This works great, but seeing that .net core now provides me with an out of the box DI container, I would much rather like to use that - There is just one problem compared to the Unity IOC, namely that it is injected as a constructor argument, and not resolved like the example above.
In most cases, I figured that it forces me to chain my dependencies throughout multiple classes, instead of just resolving my dependency in the classes that actually needs them.
I have been looking at ways to solve this, and as far as I can see, the only option is to do something like this:
Public class TestClass {
public TestClass(IServiceProvider serviceProvider)
{
var instance = serviceProvider.GetService<InterfaceClassToResolve>();
}
}
And then we are back to square one again...
Therefore, am I missing some of the functionality behind the .net core IOC, or is there some secret sauce to why most examples wants me use the .net core IOC via constructor arguments?
You can use DI without constructors like:
On the ConfigureServices
services.AddSingleton<YourClass>()
Then inject it like this:
private YourClass YourClass
{
get
{
return this.serviceProvider.GetRequiredService<YourClass>();
}
}
As already commented, Service Locator pattern is not the best method and considered an anti-pattern.
I understand the necessity, though, of finding a way to easily convert existing code to the out-of-the-box DI system without going mad.
I therefore suggest you to do something like this:
1) Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DatabaseContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// other services configuration here
// IMPORTANT: This should be the last line of ConfigureServices!
IOC.CurrentProvider = services.BuildServiceProvider();
}
...
2) IOC.cs
public class IOC
{
public static IServiceProvider CurrentProvider { get; internal set; }
public static T resolve<T>()
{
return CurrentProvider.GetService<T>();
}
}
This should allow you to use dotnet core DI with existing service locator code based on Unity, with minimal fixes (basically just some using declarations to be fixed), as long as you solemnly promise to refactor your code as soon as possible to get rid of all that Service Locator code :D
I've got some code that's accessing the HttpContextBase.Trace object and doing some things with it (checking IsEnabled, writing some messages). The problem is that it's a System.Web.TraceContext object. TraceContext is a sealed class with only one constructor: that takes an HttpContext object. Moq is unable to mock either TraceContext or HttpContext. Can I do anything here to test this code with Moq?
Or will I need to factor this code out and stop referring to HttpContextBase.Trace?
I sort of hate answers that say "don't do that" because there might be value in the answer, regardless of the approach, however, here we go:
Don't do that.
Let's assume you have this class:
public class MyCode
{
public void Do()
{
HttpContext.Current.Trace.WriteLine("WOO!");
}
}
This kind of thing isn't very testable. If you wanted to refactor for testability, you could use more of an "inversion of control" type of method. Here I'll use "dependency injection" (there are other options, like "service location" and "abstract factories", but this is easiest to understand):
public class MyCode
{
private IMyLogger _logger = null;
public MyCode(IMyLogger logger)
{
_logger = logger;
}
public void Do()
{
_logger.TraceWriteLine("WOO!");
}
}
Now you can see that this code is very testable and you don't have to jump through hoops to mock anything.
//Confirms "Do" method calls "TraceWriteLine"
public void Do_Called_CallsTraceWriteLine()
{
//Arrange
var loggerMock = new Mock<IMyLogger>();
loggerMock.Setup(l => l.TraceWriteLine(It.IsAny<string.());
var target = new MyCode(loggerMock.Object);
//Act
target.Do();
//Assert
loggerMock.VerifyAll();
}
Now your implementation of IMyLogger might call out to HttpContext, but it keeps your target class testable.
public DefaultLogger : IMyLogger
{
public void TraceWriteLine(string message)
{
HttpContext.Current.Trace.WriteLine(message);
}
}
To implement such a thing, many people choose to use an Inversion of Control container. You don't have to do this, but it makes things a little simpler and doesn't decrease maintainability as you add more dependencies. You can imagine if you had an interface for each part of the .NET framework that was untestable, your "new MyCode" constructor calls would start to get quite long. IoC containers help you avoid this.
Popular IoC containers for .NET:
Ninject
Unity
MEF (builtin to .NET 4.0)
Autofac
Castle Windsor
StructureMap
Your post is tagged "ASP.NET". Hopefully you are using MVC. If so, it has new support for dependency injection, examples here:
http://weblogs.asp.net/shijuvarghese/archive/2011/01/21/dependency-injection-in-asp-net-mvc-3-using-dependencyresolver-and-controlleractivator.aspx
Hopefully this helps. Sorry it doesn't directly answer your question.
I would like to just markup a property with an attribute [DoInjection] and have unity do the injection. I don't want to have to use prop = Unity.Resolve(type). Thats a pain and messy. Does unity provide attributes to do this or do I have to build my own?
Edit: register in App.Main
ISessionFactory sf = new SessionFactory();
container.RegisterType<IRepository, CustomerRepository>(new InjectionConstructor(sf.CurrentUoW));
container.RegisterInstance<IUnitOfWork>(sf.CurrentUoW);
Using [Dependancy] on IUnitOfWork propery in ClassX other class but it's always null. Do I need to build ClassX instance using Unity to get this to work? It looks like I do have to. I don't like that.
Unity has a DependencyAttribute you can use for this:
public class MyObject
{
private SomeOtherObject _dependentObject;
[Dependency]
public SomeOtherObject DependentObject
{
get { return _dependentObject; }
set { _dependentObject = value; }
}
}
http://msdn.microsoft.com/en-us/library/ff650198.aspx
Based on your question, it sounds like you might be trying to use Unity in the wrong spot and your design sense was telling you it didn't feel right. You should only see Unity where you bootstrap your application. That's your Main method in a console app or Global.asax in a web or wcf app. The idea is to keep relying on dependencies all the way up the chain until you get to where you bootstrap and resolve just that one top level object using your IoC container. In a console app, I do this:
class Program
{
static void Main(string[] args)
{
using (var container = new UnityContainer())
{
container
.AddExtension(new ConfigureForConsole(args))
.Resolve<MyApplication>()
.Execute();
}
}
}
http://www.agileatwork.com/console-application-with-ioc/
In this case, MyApplication is my top level object (it doesn't need to be an interface here). The ConfigureForConsole is just a one-off custom container extension that has all the RegisterType lines in there. Alternatively you could initialize the container from App.Config here. The idea though is that your Main method has almost nothing in it. Another benefit of this approach is that it makes your code more portable. I find that console apps usually turn into windows services and keeping things clean here makes that transition pretty painless.
I have a bunch of types registered with Autofac and some of the dependencies are rather deep. Is there a built in way to test that I can resolve all registered types? I want to fail fast at application startup, and not several minutes later part way in.
This is what I'm currently doing, and it seems to work, but I still wonder if there isn't a better way.
public void VerifyAllRegistrations()
{
foreach (IComponentRegistration registration in _container.ComponentRegistrations)
{
bool isNewInstance;
registration.ResolveInstance(_container, new Parameter[0], new Disposer(), out isNewInstance);
}
}
private class Disposer : IDisposer
{
public void Dispose()
{
// no-op
}
public void AddInstanceForDisposal(IDisposable instance)
{
instance.Dispose();
}
}
Autofac doesn't offer anything to that effect - because Autofac creates components in response to ResolveInstance, you're going to be faced with constructor side-effects etc.
Integration testing is the best way to address this.