Plugin Achitecture Extensibilty - c#

I am working with MEF to get a plug in architecture going. I want to design in some extensibility. I want to extend initialization.
What I have is a "driver" which repetively collects data from some source. These are my plugins. Each of these plug ins needs to be initialized. Right now I have an interface that these plugins are required to implement.
interface IDriverLiveCollection
{
ILiveCollection GetCollection(ILog logger, IDriverConfig config);
}
This Interface is basically creating an instance of a ILiveCollection from the plugin. for better understanding ILiveCollection looks like this.
interface ILiveCollection
{
void GetData(Parameter param, DataWriter writer);
void ShutDown();
}
And also the initialization loop:
foreach(IDriverConfig config in DriverConfigs)
{
//Use MEF to load correct driver
var collector = this.DriverLoader(config.DriverId).GetCollection(new Logger, config);
// someTimer is an IObservable<Parameter> that triggers to tell when to collect data.
someTimer.Subscribe((param)=> collector.GetData(param, new DataWriter(param)));
}
The problem is that some driver may require more information than their configuration in order to initialize. For example, some driver would like a set of parameters given to them during initialization.
I could easily extend the interface to now look like:
interface IDriverLiveCollection
{
ILiveCollection GetCollection(ILog logger, IDriverConfig config, IEnumerable<Parameter> params);
}
The down side to this approach is that the public interface has changed and now i need to recompile EVERY driver even though none of the have needed this parameter list in order to function before. I intend on having ALOT of drivers and I will also not have any control over who writes drivers.
I thought up another solution. I could create interfaces and inside my loop between when I call Get Collection and before i subscribe to the timer, i could check if the ILiveCollection object also extends one of these interfaces:
interface InitWithParameters
{
void InitParams(IEnumerable<Parameter> params);
}
in my loop:
foreach(IDriverConfig config in DriverConfigs)
{
//Use MEF to load correct driver
var collector = this.DriverLoader(config.DriverId).GetCollection(new Logger, config);
// Check to see if this thing cares about params.
if(collector is InitWithParameters)
{
((InitWithparameters)collector).InitParams(ListOfParams);
}
// Continue with newly added interfaces.
// someTimer is an IObservable<Parameter> that triggers to tell when to collect data.
someTimer.Subscribe((param)=> collector.GetData(param, new DataWriter(param)));
}
The difference here is that I will not need to recompile every driver in order to get this to work. Old drivers will simply not be of type InitWithParameters and will not be called that way while new drivers will be able to take advantage of the new interface. If an old driver wants to take advantage, then it can simply implement that interface and be recompiled. The bottom line: I will not need to recompile drivers UNLESS they want the functionality.
The downsides that I have recognized are: I will obviously need to recompile which ever program is in this loop. There becomes a versioning issue when a new driver is used with an old version of the program with the loop which could result in some issues. and finally I have to hold a huge list of every possible type in the program with the loop as these things grow.
Is there a better way to do this?
Edit Additional Info:
I am attempting to use MEF on the IDriverLiveCollection, not on ILiveCollection since IDriverLiveCollection allows me to construct a specific ILiveCollection with custom initialization parameters.
It is possible to have 2 ILiveCollections of the same type (2 FooLiveCollections) each with a different ILog and IDriverConfig and potentially IEnumerable. I would like to be able to specify these during the "initialization loop" and not at the time of composition of the plugins.

If you just use [ImportMany] directly on your ILiveCollection interface, you could handle this entire infrastructure via the [ImportingConstructor] attribute.
This allows your plugins to specify exactly what they need to be able to be constructed, without having to provide and construct the types later.
Effectively, your host application would need nothing but:
// This gets all plugins
[ImportMany]
IEnumerable<ILiveCollection> LiveCollections { get; set; }
Each plugin would then have their type that exported this, ie:
[Export(typeof(ILiveCollection))]
public class FooLiveCollection : ILiveCollection
{
[ImportingConstructor]
public FooLiveCollection(ILog logger, IDriverConfig config)
{
// ...
Or, alternatively, a plugin could leave off one constructor argument, or add laters (without effecting previous plugins), ie:
[ImportingConstructor]
public BarLiveCollection(ILog logger, IDriverConfig config, IBarSpecificValue barParam)
{
// ...

Related

Injecting dependencies with runtime dependencies

I'm building an application that performs actions initiated by a user and one particular class has dependencies on things I can wire up in DI such as an ILogger instance as well as an HttpClient in addition to runtime arguments that identify the user and the instance of the action (mostly to be used while logging to help with debugging).
The trouble I have is that I'm not entirely sure how to inject this class into the other classes that need it as a result of the runtime dependencies.
Here's a simplified example of one of my classes:
public class Dependency : IDependency
{
private readonly HttpClient httpClient;
private readonly ILogger<Dependency> logger;
private readonly RuntimeDeps runtimeDeps
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
RuntimeDeps runtimeDeps)
{
// set private fields
}
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{runtimeDeps.InstanceId} failed. " +
"Initiated by {runtimeDeps.UserName}");
}
}
This feels like it requires a factory to create but then is it best to request the HttpClient and Logger in the factory method or declare it as a dependency of the factory? If the latter, I presume the factory would have to be registered as a transient or as a scoped resource since registering it as a singleton would result in a captive dependency (I think).
Any suggestions on redesigns are also welcome if this is a symptom of a poor design. I'd love to implement Mark Seeman's Pure DI to get some more assistance from the compiler but I don't know if that's possible in Azure functions.
A transient factory with the transient dependencies injected into the constructor and the runtime dependencies as parameters of the Create method will work fine.
DI is baked into the Azure Functions library in the sense that parameters are injected into the trigger methods, but beyond these you should be able to use Pure DI to manage your own dependencies by calling into some composition root helper class from the trigger function which knows how to build your dependency graph in a pure manner.
Instead of requiring runtime data during the construction of a component, it's better to let runtime data flow through method calls on an initialized object graph by either:
passing runtime data through method calls of the API or
retrieving runtime data from specific abstractions that allow resolving runtime data.
I formalized this in 2015 in this blog post, which I referred to in the comments.
After reading your additional comments, I came to the conclusion that in your case option 2 is most suited, as the data you are sending is likely an implementation detail to the component, and should not be part of the public API.
In that case, you can redesign your component as follows:
public class Dependency : IDependency
{
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
IRuntimeDepsProvider provider) ...
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{provider.InstanceId} failed. " +
$"Initiated by {provider.UserName}");
}
}
IRuntimeDepsProvider is an abstraction that hides the retrieval and storage of runtime data. This gives you the ability to postpone the decision to either use a Closure Composition Model or an Ambient Composition Model until the Last Responsible Moment.
Using the IRuntimeDepsProvider abstraction, you can chose to set the incoming runtime values after the object graph is constructed. For instance:
public class MyFunction
{
// Notice the different abstraction here
public MyFunction(
IRuntimeDepsInitializer initializer,
IHandler<Something> handler) ...
public void TheFunction(Guid instanceId, string userName, Something cmd)
{
// Setting the runtime data *after* the object graph is constructed,
initializer.SetData(instanceId, userName);
// but before the graph's public methods are invoked.
handler.Handle(cmd);
}
}
Here, a second abstraction is introduced, namely IRuntimeDepsInitializer. Now you can have one class implementing both interfaces:
public class RuntimeDepsStorage : IRuntimeDepsInitializer, IRuntimeDepsProvider
{
public Guid InstanceId { get; private set; }
public string UserName { get; private set; }
public void SetData(Guid id, string name)
{
InstanceId = id;
UserName = name;
}
}
TIP: Instead of using two interfaces, you can also use only IRuntimeDepsProvider and let MyFunction depend on the concrete RuntimeDepsStorage. Which solution is best depends on the context.
Now the main trick here is to make sure that RuntimeDepsStorage becomes a Scoped dependency, because you want to reuse it throughout a request, but not shared by multiple requests.
When applying Pure DI, this would look like this:
var storage = new RuntimeDepsStorage();
new MyFuncion(
initializer: storage,
handler: new SomethingHandler(
stuffDoer: new Dependency(
httpClient: client, // Did you notice this is a runtime dep as well?
logger: new Logger<Dependency>(),
provider: storage)))
If, on the other hand, you would be using MS.DI as your DI Container, registration would be similar to the following:
services.AddScoped(_ => new RuntimeDepsStorage());
services.AddScoped<IRuntimeDepsProvider>(
c => c.GetRequiredService<RuntimeDepsStorage>());
services.AddScoped<IRuntimeDepsInitializer>(
c => c.GetRequiredService<RuntimeDepsStorage>());
// etc, your usual registrations here

How to properly implement ILogger.IsEnabled() in custom logger in ASP.NET Core MVC

I am (as something of a novice) implementing my own custom logger for use in ASP.NET Core MVC apps. I have this logger working functionally in every regard. But I cheated a little so far, namely I implemented the ILogger.IsEnabled method as follows:
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
Functionally, this works fine, since the framework ensures that the Log() method is only invoked if the log level is at or higher than the one specified. So the correct "things" are being logged and the lower-level "things" are not being logged as expected.
However, I also want to support the following kind of situation in my code, where _logger is typed as ILogger and is properly injected in my controller:
if (_logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug("This is an expensive message to generate: " +
JsonConvert.SerializeObject(request));
}
To make this effective, my IsEnabled() method should be able to know what the log level IS for the instance of the logger that was created with my LoggerProvider, but I don't know how to get that information directly, or how to pass it properly to the injected instance of the the logger I am working with.
Complex examples and tutorials I have been able to find seem to be constructed in every case for console app types, not network app types, and so far I have been unsuccessful at figuring out how to do this through the templated Startup class in ASP.NET MVC.
What is the simplest and most effective way to stop cheating at my custom IsEnabled() method in order to avoid the unnecessary serialization (in my example) if none of the registered loggers in the injected instance are handling the Debug log level? Or do you have a favorite example or tutorial in the ASP.NET core setting you can point me to?
You can take a look at built-in loggers source code and see how they implement it.
In short, they only check that logLevel != LogLevel.None, but depending on the logger logic, you might also want to check some other configuration. For example, DebugLogger logger also checks the Debugger.IsAttached property and EventLogLogger checks the EventLogSettings.Filter (supplied via constructor).
Update
To make this effective, my IsEnabled() method should be able to know what the log level IS for the instance of the logger that was created with my LoggerProvider, but I don't know how to get that information directly, or how to pass it properly to the injected instance of the the logger I am working with.
You can create an implementation of ILoggerProvider which in turn can make use of dependency injection to get the configuration you want. If you want to use the options pattern to configure it, you must do something along the lines of:
public class MyLoggerProvider : ILoggerProvider
{
private readonly IOptions<MyLoggerOptions> _options;
public MyLoggerProvider(IOptions<MyLoggerOptions> options)
{
_options = options;
}
public ILogger CreateLogger(string name)
{
return new MyLogger(name, _options.Value);
}
}
And optionally add an extension method to make registration easier:
public static class MyLoggerExtensions
{
public static ILoggingBuilder AddMyLogger(this ILoggingBuilder builder, Action<MyLoggerOptions> configure)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, MyLoggerProvider>());
LoggerProviderOptions.RegisterProviderOptions<MyLoggerOptions, MyLoggerProvider>(builder.Services);
builder.Services.Configure(configure);
}
}

How to call constructor of class which are instantiated through Structure Map in C#

I have an interface called ILogger which basically contains some methods for logging.
Ilogger.cs
public interface ILogger
{
void LogError(string message, Exception exception = null);
void LogMessage(string message);
void LogValidationError(UploadResult uploadResult);
void LogValidationError(ValidationResult validationResult);
void LogProcessingError(string processingError);
}
I have a LogHelper class which implements this interface. The LogHelper class is instantiated through StructureMap like
ObjectFactory.Initialize(
request =>
{
request.For<ILogger>().Singleton().Use<LogHelper>();
});
I have many classes in whose constructor I just instantiate this class and call methods to log the information.
For eg: I have a class say Dummy1 in whose constructor I instantiate the LogHelper as:
public Dummy1()
{
this.logger = ObjectFactory.GetInstance<ILogger>();
}
In LogHelper I have method which basically creates log file and writes the message passed as parameter to it.
public void LogMessage(string message)
{
using (var writer = this.GetTextWriter(this.messageFilename))
{
writer.WriteLine(message);
}
}
Currently the filename is hardcoded into a constant property of LogHelper class as private string messageFilename = "logs\\UserCreationResult.log";
But I want the Filename to be dynamically sent whenever the LogHelper is instantiated.
I thought of having a class property and define that property in the constructor whenever the class is instantiated. But since the LogHelper class is instantiated as ObjectFactory.GetInstance<ILogger>(). I am not able call the constructor in which I can pass the filename.
Unfortunately the way you are going about this is a little bit self-defeating. Your classes only know about ILogger, not any particular implementation of ILogger. That's good - it means that the implementation could write to a file, a SQL table, or anything.
But if your class only knows about ILogger, not the implementation, then how does your class know that the logger needs a file path? If you change your method signatures in ILogger to contain a file path, then two things happen.
It becomes impossible to have any implementation of ILogger that doesn't write to a file (unless it ignores the file path, which would be really weird.)
Now that class that calls the logger has to know a file path. Where will that class get a file path from? Will it be stored in the class? In that case you end up with a class that doesn't work unless it's part of an assembly executing on a computer where it can write to that exact file path.
Instead, the details of where and how to log should live somewhere in your ILogger implementation. That's closer to the Single Responsibility Principle. The class that calls ILogger isn't responsible for decisions about how ILogger works. It doesn't know and it doesn't want to know. It says "Here, take this and log it." The logger implementation is responsible for the rest.
I'd recommend scrapping the static ObjectFactory entirely and using the container to resolve and create all of your classes, including the logger and the classes that depend on it, but that's so broad that it's not really helpful. (It has been deprecated because it's a bad pattern. It's not even in the latest version of StructureMap.)
Everything above this is a recommendation. After this I'm offering an option that's not really recommendable, but requires less change and keeps your classes from knowing about file paths, because please don't do that ever.
One option - a halfway compromise - might be to register different named implementations of ILogger. You could modify your logger class to look like this:
public class FileLogger : ILogger
{
private readonly string _filePath;
public FileLogger(string filePath)
{
_filePath = filePath;
}
}
Now you can create multiple instances of that logger class, passing a different file path to each one. That way it's not a static property, which limits you to only having one file path.
Then you could register your implementations like this.
ObjectFactory.Initialize(
request =>
{
request.For<ILogger>().Singleton()
.Use<FileLogger>(() => new FileLogger("some path")).Name = "LoggerOne";
request.For<ILogger>().Singleton()
.Use<FileLogger>(() => new FileLogger("some other path")).Name = "LoggerTwo";
});
Now your class can say which logger it wants, like this:
var logger = ObjectFactory.GetNamedInstance<ILogger>("LoggerOne");
But please don't really do that either. It's more than I can really describe here in great detail, but take a look at dependency injection so that your classes really only know about ILogger and don't know or care which implementation they get and don't tell it anything about how to do its job.
You are using your logger as a singleton, so you are not creating an instance each time you call ObjectFactory.GetInstance<ILogger>();, you are simply getting a reference to the same logger instance all the time which is created once on first use.
If you want to write to a specific destination, then the best solution is to specify the destination in the Logging methods:
void LogError(string message,
Exception exception = null,
string destination = /*some adequate defualt value*/);
void LogMessage(string message,
string destination = /*some adequate defualt value*/);
Creating state information in your logger instance with a specific destination can be dangerous if you are using the logger concurrently from methods that are expecting and therefore setting different destinations; you can end up logging things where they are not supposed to.
Which brings up an important issue; because you are sharing the logger across your application (singleton) make sure its methods are safe to call concurrently if there is a possiblity that it will be called this way.

Winforms IOC Container - Composition Root

I've recently been dabbling a bit with IOC Containers (LightInject in my case).
I've been reading that you should only need to use the container ONCE, on startup, and no where else. This is what I'm struggling to understand. If I can only reference the container in a bootstrap/startup method, how is it possible to resolve what I need, elswhere in the project, or at runtime if the class depends on user input.
So In my Traditional Windows Forms App, on Form Load Say, I would Bootstrap Lightinject as per the below code. It's only an arbitrary example, it's more the premise I need to get my head around.
I might be missing something here entirely, or just not getting it. But how am i supposed to resolve dependancies, If i can't use/not supposed to reference or use Container.GetInstance/Resolve/{Choose IOC Syntax Here}, and only in the composition root.
For Instance, Say I have two buttons and a TextBox on my form. The first button gets me an ILoader (below code), and the second button loads up a file viewer (ILoader, below code), whose file name is what is entered into the textbox on the winform.
Without An IOC Container I would do the following (let's just assume its put in the click event)
Button 1 Click Event :
ISplitText MyStringFunc = new WhateverImplementsIt();
Button 2 (gets the file reader based on textbox input)
ILoader MyLoader = new FileReaderImplementation(TextBox1.Text);
Using LightInject, I'm surely compelled to do the following:
Button1 Click:
ISplitText Splitter = Container.GetInstance<ISplitText>();
Button 2 Click
var LoaderFunc = Container.GetInstance<Func<string, ILoader>>();
ILoader l2 = LoaderFunc(TextBox1.Text);
Am I Incorrect? In A large project I would have Container.GetInstance, peppered all over the place, in the main form file and elsewhere surely, so how can i only reference the container in ONLY 1 spot, in the form of bootstrap, am i missing a magic piece of the puzzle?
In all the sample apps I have seen it's all done in one simple console app, in the Main function. All these apps follow the format of:
Container = new Container();
Container.Register<IFoo,Foo>();
Container.Register<IBar,Bar();
var Resolved = Container.GetInstance<IFoo>();
Well, I understand all that, and it's extremely simple. It's once you start adding a bit of complexity to the app itself, I'm lost as to how to get the instances without making the Container itself public, or static, or accessible in some way,shape or form and then calling Container.GetInstance in a million places (which apparently, is a big no no). PLEASE HELP!
Cheers,
Chud
PS - I am not concerned about "abstracting the container" itself. so would prefer to only focus on increasing my understanding of the above.
public class BootStrapIOC
{
public ServiceContainer Container;
public BootStrapIOC(ServiceContainer container)
{
Container = container;
}
public void Start()
{
Container.Register<ISplitText, StringUtil>();
Container.Register<string, ILoader>((factory, value) => new FileViewByFileName(value));
}
}
//HUH? How can i NOT use the container??, in this case in the button_click
ILoader Loader = Container.GetInstance<Func<string, ILoader>>();
ILoader l2 = Loader(TextBox1.Text);
ISplitText Splitter = Container.GetInstance<ISplitText>();
EDIT #1
OK, so, after re-reading the comments and looking at a few more examples on the interweb, I think I may finally understand it. The issue was (I think) is that i wasn't thinking "higher level" enough. I was trying to resolve my dependancies in my winforms application, AFTER the form had already been constructed,and in the form itself. When in reality, it's too late by then. I wasn't viewing the "form itself" as just another object, which needed it's dependencies injected into it.
So I bootstrap now in my Program.cs:
static class Program
{
private static ServiceContainer Container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Container = new ServiceContainer();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
BootStrapIOC Strap = new BootStrapIOC(Container);
Strap.Start();
//This magic line resolves EVERYTHING for me required by the Form
var form = Container.GetInstance<Form1>();
Application.Run(form);
//Application.Run(new Form1());
}
}
My question now is, Is my line of thinking now correct in terms of winforms. It seems to make more sense, changing my approach to "higher up" the chain and resolving from Program.cs??
Secondly, And I'm not sure if this calls for a new question altogether, please advise as I am an SO noob.
How would I setup a factory to return the correct instance of an object? One of the original comments indicated that that would be a usage in this scenario. Let's use a contrived example.
Where I needed an object, but don't know which object until run time/user input.
My Idea:
BootStrap
Container.Register();
Factory Interface and Implementation:
Let's put some optional parameters in also, as I want to know if this is the correct/best way to do it?
public interface IFileViewerFactory
{
ILoader GetFileViewer(string FileName, string Directory = null, bool CreatingDirectory = false);
}
public class FileViewerFactory:IFileViewerFactory
{
public FileViewerFactory() { }
public ILoader GetFileViewer(string FileName, string Directory = null, bool CreatingDirectory = false)
{
if (CreatingDirectory == false)
{
if (Directory == null)
return new FileViewByFileName(FileName);
else
return new FileViewByDirectoryName(Directory, FileName);
}
else
return new FileViewByDirectoryNameCreateDirectoryOptional(Directory, FileName, CreatingDirectory);
}
}
Form:
public IFileViewerFactory FileViewerFactory { get; set; }
Button Click:
ILoader FileLoader = FileViewerFactory.GetFileViewer(TxtBoxFileName.Text);
Or:
ILoader FileLoader = FileViewerFacotry.GetFileViewer(TxtBoxFileName.Text,TxtBoxDirectory.Text);
So to finish off, my questions are:
Is my new way of "higher level" thinking, and bootstrapping from Program.cs now correct
How Can I handle optional parameters in LightInject
Is How I have setup my factory the correct way to do it?
Let's forget about the Fugliness of the factory and just try to work on the mechanics of the questions :)
I know it's a bit late to answer a question that is over a year old but let me try.
The issue here is that you don't want your container to go out anywhere else than your Composition Root. In a complex solution consisting of mutliple assembiles, this means the container itself is only referenced by the topmost assembly (where the Composition Root is).
But the application stack is usually complex, you possibly have multiple assembiles and still, your depencencies should be resolves across the application.
Historically, one of the possible approaches was the Service Locator pattern. The locator goes down to the very bottom of the stack and from there, it offers a service that resolves dependencies. Thus, it's available anywhere up the stack.
This approach has two drawbacks, first is that your container is referenced at the very bottom of the stack and even if you circuvment this you still have your locator referenced everywhere. The latter could be painful in a large app as you possibly have some standalone assembiles that you don't want to be forced to reference your locator (or anything else).
The ultimate solution is called the Local Factory (aka Dependency Resolver) and it takes care of creating just few of its dependand services. The trick is then to have multiple local factories across your app.
A typical setup is like this. Suppose there's an assembly, call it A, that the client will use to obtain an instance of IServiceA. The assembly contains only the two:
interface (obligation) of the service - IServiceA
the local factory clients will use to obtain instances of the service
And that's all, no other references, no containers. There's even no implementation at this point yet. The trick here is to make the factory open for the actual provider - in a sense that the factory doesn't even yet know how to create instances - it's the Composition Root that will tell it.
// Assembly A
public interface IServiceA
{
...
}
public class ServiceAFactory
{
private static Func<IServiceA> _provider;
public static void SetProvider( Func<IServiceA> provider )
{
_provider = provider;
}
public IServiceA Create()
{
return _provider();
}
}
the provider here has a functional contract but it could also be expressed as an interface
And that's all, although there's no implementation in the factory at the moment, the client code is suddenly very stable:
// client code to obtain IServiceA
var serviceA = new ServiceAFactory().Create();
Note again how self-contained this assembly A is. It has no other references, still, it offers a clean way to obtain instances of your service. Other assemblies can reference this assembly with no other additional references.
Then comes the Composition Root.
At the very top of your stack, your main assembly references the assembly A and some other assembly, let's call it AImpl that contains a possible implementation of the service interface.
technically the implementation of the service could be in the very same assembly the interface is but it only makes things easier
The Composition Root creates the provider of the factory by delegating a factory method down the stack, to the assembly A
// Composition Root in the top level module
// Both assemblies
// * A that contains IServiceA
// * AImpl that contains an implementation, ServiceAImpl
// are referenced here
public void CompositionRoot()
{
ServiceAFactory.SetProvider( () =>
{
return new ServiceAImpl();
} );
}
From now on, the provider is set up and all the client code down the stack that uses the factory, can succesfully obtain instances.
The Composition Root provides all other implementations of other local factories, as well. There are multiple setups then in the Composition Root:
SomeLocalFactoryFromAssemblyA.SetProvider( ... );
AnotherLocalFactoryFromAssemblyB.SetProvider( .... );
...
Where is your container then?
Well, the container is just one possible implementation of the provider. It only helps rather than spoils. Note however that you don't even have to use it, it's a choice rather than obligation.
public void CompositionRoot()
{
var container = new MyFavouriteContainer();
container.Register<IServiceA, ServiceAImpl>(); // create my registrations
ServiceAFactory.SetProvider( () =>
{
// this advanced provider uses the container
// this means the implementation, the ServiceAImpl,
// can have possible further dependencies that will be
// resolved by the container
container.Resolve<IServiceA>();
} );
}
This is the most clean setup I am aware of. It has all desired features:
it separates concerns in a clean way
the client doesn't really need any other dependencies than the service contract and the factory
the client doesn't even know there is or will be a container, in fact the client doesn't care
in a test environment, providers can easily be setup without any container, to provide static mocks of your services
the Composition Root is a real composer here - it's the only place in your code where the three: interfaces, implementations and the container, meet together

Unity - resolving dependencies based on some condition

I have layered asp.net MVC application.
In the service layer, I have a container to register dependencies. e.g:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ISomething, Something>();
}
Based on the design, we need to have a mock implementation of the
classes if the user decided to open the application for testing purpose.
So, I came up with an Idea like
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ISomething, Something>();
container.RegisterType<ISomething, SomethingMock>();
}
If I use a flag somewhere to indicate whether or not system runs at testing mode, how can I make a decision on which dependency to resolve at the runtime?
If it is not an elegant solution, what could be the alternative?
If I use a flag somewhere to indicate whether or not system runs at testing mode, how can I make a decision on which dependency to resolve at the runtime?
You should not change the structure of your object graph based on runtime decisions. This is very much related to the anti-pattern of injecting runtime data into components.
In case you require to switch implementations based on runtime conditions (meaning: the value might change from request to request), the solution is to create a proxy class that implements ISomething and wraps the two ISomething implementations (this article shows some examples of proxy implementations). When ISomething.Method is called, it can forward the call to the right implementation, based on the runtime condition that it determines at that point.
In your case however, you are most likely not talking about runtime conditions, but about a configuration value. Configuration values don't change during the lifetime of the application. Only after a restart (or redeploy) you would typically see a change of value.
That means that you can simply read the configuration value at startup and decide at that point which implementation should be registered:
if (bool.Parse(ConfigurationManager.AppSettings["Production"]))
{
container.RegisterType<ISomething, Something>();
}
else
{
container.RegisterType<ISomething, SomethingMock>();
}
While I fully support Stevens answer and his considerations, there is technically a way to do what you intended.
You can use named registration:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ISomething, Something>();
container.RegisterType<ISomething, SomethingMock>("SomethingMock");
}
and then use a string parameter to resolve it:
string s= "";
var mySomething = container.Resolve<ISomething>(s); // will return standard implementation
s = "SomethingMock"
var mySomething = container.Resolve<ISomething>(s); // will return mock implementation
you would need to intercept when asp wants to resolve ISomething.
For reference see
https://msdn.microsoft.com/en-us/library/ff660923%28v=pandp.20%29.aspx
Now it's up to you which way you go.

Categories

Resources