Unity constructor injection with implied names - c#

I am trying to inject two classes into my constructor, the problem they are both of the same interface. My registering is:
container.RegisterType<ITrackerSection, ScopeSection>();
container.RegisterType<ITrackerSection, SampleSection>();
As you can see they are both of type ITrackerSection but have different implementations. My constructor looks as follows:
public TrackerEngine(ITrackerSection scopeSection, ITrackerSection sampleSection)
Both these parameters are injected as a sampleSection as it was last to be registered for the interface type. I have no problem with naming the registered types for example
container.RegisterType<ITrackerSection, ScopeSection>("scopeSection");
container.RegisterType<ITrackerSection, SampleSection>("sampleSection");
But this now means I have to specify the classes parameters and that seems messy and adding dependency when unity is more than capable of resolving them. Furthermore the registering of the TrackerEngine would also need to specify the parameters. I know I could use an in line attribute in the constructor of TrackerEngine but I would prefer Unity to infer the objects by the names.
Can Unity (I can not seem to get this working) correctly inject the correct implementation of the interface purely from the name given to the parameter in the constructor? So ITrackerSection scopeSection is the same name given in the registering of ScopeSection so use that type.

I agree with the comments regarding sharing the interface. The whole point of IOC is that your engine should not need to know which implementation to use. It should only be given the interface.
A way to solve this is to allow Unity to inject an array of interfaces:
public TrackerEngine(ITrackerSection[] trackerSections) { }
This way you can inject both. But then, if you really need to know which interface is which, you could implement a enum or something in your interface. Something like this:
public interface ITrackerSection {
SectionType Section { get; }
}
public enum SectionType{
0 = Scope,
1 = Sample
}
And in your implementation:
public class ScopeTrackerSection : ITrackerSection {
// Do your stuff...
public SectionType Section {
get { return SectionType.Scope; }
}
}
public class SampleTrackerSection : ITrackerSection {
// Do your stuff...
public SectionType Section {
get { return SectionType.Sample; }
}
}
And in your Engine, you can fetch the interface needed to the desired action.
public TrackerEngine(ITrackerSection[] trackerSections) {
var scopeTrackerSection = trackerSections.FirstOfDefault(x => x.Section == SectionType.Sample);
// Do something with scopeTrackerSection
}

Related

Ninject Dependency Injection - Two Concrete classes

I am learning Ninject for dependency injection and have a use case where two classes implement the same interface in a WPF MVVM applicaiton. In my research the dependencies can be bound using contextual bindings, however I am unsure of how that would work in this scenario.
For example:
public interface IModifyContent {
string ModifyOperation();
}
public class UpdateContent : IModifyContent {
public string ModifyOperation() {
return "This is the update operation";
}
}
public class DeleteContent : IModifyContent {
public string ModifyOperation() {
return "This is the delete operation";
}
}
public class ModifyFile {
private IFileManager _fileManager;
private IModifyContent _modifyContent;
public ModifyFile(IFileManager fileManager, IModifyContent modifyContent)
{
_fileManager = _fileManager;
_modifyContent = modifyContent;
}
public void Modify()
{
var fileContent = _fileManager.ReadFileContents(); // Returns file content
var result = _modifyContent.ModifyOperation(); // ModifyOperation would actually modify content in some way...
// Do stuff with result
}
}
Then the binding would look something like this:
Bind<IModifyContent>().To<UpdateContent>();
Bind<IModifyContent>().To<DeleteContent>();
// Other bindings
In this my thinking is as follows:
ModifyFile class is used for common funcitonaility when modifying a file, whereas the two concrete implementations of IModifyContent define the unique behaviour that can occur for the different operations.
Depending on what calls/ invokes ModifyFile I want to pass in a different concrete implementation of IModifyContent. I.e When calling from update business logic or view model, then the concrete UpdateContent should be passed as the dependency to ModifyFile.
Firstly is this a good design approach to avoid repeating common logic and secondly how can I inject the correct concrete implementation depending on what class/ invokes ModifyFile?
There is a way through which you can achieve this !!!
You can register dependencies with specific name.
IKernel ninjectKernel = new StandardKernel();
// Defining Bindings with specific names
ninjectKernel.Bind<IModifyContent>().To<UpdateContent>().Named("Update");
ninjectKernel.Bind<IModifyContent>().To<DeleteContent>().Named("Delete");
You can resolved these dependencies at compile time as shown below:
// Resolving dependencies using binding name
IModifyContent updateContent = ninjectKernel.Get<IModifyContent>("Update");
IModifyContent deleteContent = ninjectKernel.Get<IModifyContent>("Delete");
Once resolve they can be use to execute their codes. Below is the sample code which refers to the implementation that you have provided.
Console.WriteLine(updateContent.ModifyOperation());
Console.WriteLine(deleteContent.ModifyOperation());
// Output
// This is the update operation
// This is the delete operation
You can resolve such dependencies at run time as well.
For more information refer to the following link:
https://github.com/ninject/Ninject/wiki/Contextual-Binding
I think that if your two concrete classes are from different business flows,
you can register them as concrete classes and not by abstraction.
I mean you can register
Bind<UpdateContent>().To<UpdateContent>();
Bind<DeleteContent>().To<DeleteContent>();
And In your BusinessLogic class you can ask for concrete classes.
TLDR: The fact that two classes have the Interface, don't mean you must use them from there abstraction.

Dependency Injection and Generics

I'm having trouble with getting generics and DI to work together in an MVC Core project. I have a generic class (this is just a fragment). I need to initialize Input and Output because of how these are used in other parts of the code, so I'm using Activator to provide initial values and the new() constraint.
public class Message<TIn, TOut> :
where TIn : class, IMessagePart, new()
where TOut : class, IMessagePart, new() {
public Message(){}
public Message(TIn inpart, TOut outpart) {
Input = inpart;
Output = outpart;
}
public TIn Input { get; set; } = (TIn)Activator.CreateInstance(typeof(TIn));
public TOut Output { get; set; } = (TOut)Activator.CreateInstance(typeof(TOut));
}
I have other classes that are used by this, and they have some static utility classes. I'm trying to replace these static classes using DI.
public class Project : IMessagePart{
int y = 1;
var x = StaticUtilityClass.StaticMethod(y);
}
is used like this
var projectMessage = new Message<Project, Project>();
I'm converting the static utility classes to instance classes and injecting them. I'm using the built-in .Net core container. I converted the utilities to instance classes and registered them as concrete singletons in the container. For most things I can just do the normal-
public class SomeClass{
private readonly UtilityClass _utility;
public SomeClass(UtilityClass utility){
_utility = utility;
var x = _utility.Method(1);
}
Things work fine until I get to the generics. I can't do constructor injection on projectMessage, because the generic needs to new it up and it has the new() constraint, so I need a parameterless constructor. If I add just the an injecting constructor I get
'Project' must be a non-abstract type with a public parameterless
constructor in order to use it as parameter 'TIn' in the generic type
or method 'Message'.
and if I add both constructors Activator is only going to call the one without parameters, so DI isn't invoked. I tried using the overload of CreateInstance a few different ways, but no luck tricking it.
Any suggestions here? I don't know if I should stay with statics, try some sort of service locator approach, or if there is a different way to writing the generic.
The answer to why you are getting the error you're seeing is the new() constraints. That specifies that the parameter must have a public parameterless constructor. Which is exactly what your error says. Removing that constraint should fix that error. However, you still have another issue if you want to use DI.
Aside from IMessagePart none of your classes have backing interfaces. In order to use DI effectively you need to define an IMessage, IProject etc. Then your container can create specific instances at runtime, rather than using the Activators like you are now. So your Message declaration would look like:
public class Message<TIn, TOut> : IMessage,
where TIn : class, IMessagePart
where TOut : class, IMessagePart
{
public TIn input { get; set; }
public TOut output { get; set; }
public Message(TIn inpart, TOut outpart) {
this.input = inpart;
this.output = outpart;
}
}
You would setup your DI container something like:
public Startup()
{
var container = new DiContainer(); // I know this is the wrong name; I'm not familiar with the built in container naming and functionality.
container.Register<IMessage>();
container.Register<IMessagePart>();
container.Register<IProject>();
// Register other stuff here
}
Change the syntax there for your specific container. You also have the option of registering your instances something like:
container.Register<Message>(() => Message(part1, part2));
so that you specifically inject a Message that is newed up at Startup time, but that's not really ideal in most cases. Usually you want your DI container to dynamically create an instance as needed (hence the interfaces), rather than using a single concrete instantiation. There are exceptions of course; a SQL connection is one common one.

How to register multiple types by name using Unity?

I am new to Unity (from Castle Windsor land) so I know what I want to do with dependancy injection I am just unsure of how to do it with Unity.
Guidance would be appreciated.
And further some implementations like this:
public class Strategy
{
... etc
}
public class FooStrategy : Strategy
{
... etc
}
public class BarStrategy : Strategy
{
... etc
}
Currently I can register these one by one like this:
container.RegisterType<IStrategy, FooStrategy>("FooStrategy");
container.RegisterType<IStrategy, BarStrategy>("BarStrategy");
var foo = container.Resolve<IStrategy>("FooStrategy");
Assert.IsTrue(foo.GetType() == typeof (FooStrategy));
How can I do this more efficiently? I want to register all types implementing IStrategy by their implementation name.
container.RegisterTypes(AllClasses.FromLoadedAssemblies().Where(t => typeof(Strategy).IsAssignableFrom(t)));
It seems that by default the Name used in the container is the implementation name, so it is quite trivial in the end.
The only thing I had to change was to use a POCO as a base type, instead of an interface.

How should concrete types return an instance of an interface in a loosely-coupled way?

I have an IDirectory interface and a Directory class that implements it.
I need to create an IDirectoryEnumerator which just has a method that looks like so:
IEnumerable<IDirectory> GetDirectories();
So I created a DirectoryEnumerator class, but I'm not sure which IDirectory to return in GetDirectories(), since I want to keep my code loosely-coupled.
Should I use generics with constraints to IDirectory somehow?
Should I get it somehow through a DI container?
Should something like that be tightly-coupled and I should focus on a specific concrete type?
Or is there another better option?
Note: concrete types of IDirectory in my example don't have any default constructors and are immutable.
You could let the concrete IDirectoryEnumerator implementation accept some sort of factory (e.g. IDirectoyFactory) through the constructor, and then use a parametrized method in that factory to create concrete types of IDirectory.
This also makes testing easier and enables you to use a DI container to inject the dependencies.
EXAMPLE:
public interface IDirectoryEnumerator
{
IEnumerable<IDirectory> GetDirectories();
}
public class DirectoryEnumImpl : IDirectoryEnumerator
{
private readonly IDirectoryFactory _directoryFactory;
public DirectoryEnumImpl(IDirectoryFactory directoryFactory)
{
_directoryFactory = directoryFactory;
}
public IEnumberable<IDirectory> GetDirectories()
{
// you can use the factory here
}
}
public interface IDirectoryFactory
{
IDirectory CreateDirectory(DirectoryType directoryType);
}
public class DirectoryFactoryImpl : IDirectoryFactory
{
IDirectory CreateDirectory(DirectoryType directoryType)
{
if (directoryType == DirectoryType.DIR_A)
return new Dir_A();
// the same goes for other types.
}
}
public enum DirectoryType {
DIR_A, DIR_B, // etc ...
}

Constructor injection with non-dependency parameters

I have an interface ITradingApi like so:
public interface ITradingApi
{
IOrder CreateOrder(...);
IEnumerable<Symbol> GetAllSymbols();
// ...
}
This is meant to be a facade for the different APIs of the vendors of trading software.
My view model has a dependency on this trading API in its constructor:
public class MainViewModel
{
public MainViewModel(ITradingApi tradingApi) { /* ... */ }
// ...
}
I use Ninject as an IoC container, so I will create an instance of my view model like this:
var vm = kernel.Get<MainViewModel>();
Now, my problem:
The implementation of ITradingApi might need additional parameters to work.
Example:
One vendors API uses TCP/IP internally, so I need a hostname and a port.
Another vendor uses a COM object. Here I don't need any info.
A third vendor needs username and password of the account.
In the spirit of not allowing incomplete objects, I added these as parameters to the constructors of the concrete implementations.
Now, I am not sure, how this would work. Clearly, these additional parameters do not belong into the interface, because they are specific to each implementation.
On the other hand, these additional parameters need to be entered by the end-user and then passed to the implementation of ITradingApi, meaning that the user of ITradingApi needs intimate knowledge about the concrete implementation.
How to solve this dilemma?
UPDATE:
One approach could be to create an ITradingApiProvider that exposes a list of required parameters. The View could automatically create an input form for these parameters that is databound to the parameters in ITradingApiProvider. Now, when an ITradingApi instance is requested from the provider, it can make use of these parameters to create an instance of the concrete implementation. Clearly the implementation of ITradingApiProvider and ITradingApi are tightly coupled, but I think that is not a problem as long as each implementation of ITradingApi comes with a corresponding implementation of ITradingApiProvider.
Based on the information so far put forth here, I'd like to point out one or two things:
First of all, whether or not the concrete configuration values are supplied at composition time or truly first available at runtime as user input makes a huge difference. As long as they can be resolved at composition time things are easy because you can simply read the values from the environment and supply them to the appropriate constructors. So, for the rest of this answer I'm going to assume that things are much harder and you actually need to get those values from the user at runtime.
Instead of attempting to come up with a general-purpose configuration API I'd much rather model what's actually going on. In this case it sounds to me like we're collecting configuration values from the user, so why not model this explicitly?
Product Trader
Define an interface like this:
public interface ITradingApiTrader
{
ITradingApi Create(Type apiType);
}
Here, it's assumed that apiType can cast to ITradingApi, but this can't be enforced by the compiler. (The reason I'm calling this a 'Trader' is because this is a variation of the Product Trader pattern (PLoPD 3).)
How is this different than before?
Well, you can implement the Create method by showing a user interface for each type of ITradingApi. Each concrete user interface gathers the values required for its own concrete ITradingApi implementation and subsequently returns a correctly configured instance.
If you know the concrete types at compile time, other variations include these:
public interface ITradingApiTrader
{
ITradingApi CreateMT4TradingApi();
ITradingApi CreateFooTradingApi();
ITradingApi CreateBarTradingApi();
// etc.
}
Perhaps you can also do this (although I haven't tried to compile this):
public interface ITradingApiTrader
{
ITradingApi Create<T>() where T : ITradingApi;
}
Note also that you don't need to define the first ITradingApiTrader's Create method based on a Type - any identifier (such as an enum or string) might do instead.
Visitor
If the set of ITradingApi is (finite and) known at design time, the Visitor design pattern might also offer an alternative.
If you use a Visitor, you can make the Visit method show an appropriate user interface and then subsequently use the values collected from the user interface to create the appropriate ITradingApi instance.
Basically this is just a variation on the previous 'solution' where the Product Trader is implemented as a Visitor.
Is this what your after?
ninjectKernel.Get<MainViewModel>().WithConstructorArgument("tradingApi",
kernel.Get<ITaxCalculator>() .WithConstructorArgument("additionalParameter","someValue")));
Ok my two cents, I am not sure of anything you know. It is just to help and try...
We give a visitor to your api as construction of the interface:
public interface ITradingApi
{
Object CreateOrder();
IEnumerable<Object> GetAllSymbols();
}
public class TradingApi : ITradingApi
{
IvisitorAPI _VisitorAPI;
public TradingApi(IvisitorAPI visitorAPI)
{
_VisitorAPI = visitorAPI;
}
public Object CreateOrder()
{
var Order = new Object();
//bla bla bla
//here code relative to different visitor
_VisitorAPI.SaveOrder(Order);
return Order;
}
}
It is your visitor that knows how to handle some of the action, because depending on the visitor he will use your api in different ways to achieve the same action ( here SaveOrder).
public interface IvisitorAPI
{
bool SaveOrder(Object order);
}
public class visitorApiIP : IvisitorAPI
{
public string HostName { get; set; }
public int Port { get; set; }
public visitorApiIP(string hostname, int port)
{
HostName = hostname;
Port = port;
}
public bool SaveOrder(Object order)
{
//save the order using hostname and ip
//...
//....
return true;
}
}
Only the visitor has a knowledge of what he needs to achieve his version of the action.
Therefore it is not the APi that needs additionnal parameters, we are pushing the logic away in the visitor class.
This visitor class might be created only when ewe know who is the visitor therefore, surely at runtime
Hope it might give you some perspective. I do not know if the whole theory can be applied your exact situation.
My best anyway ;)
The solution is to use the approach as outlined in the update part of my question. ITradingApiProvider takes the role of an abstract factory and thus should be renamed to ITradingApiFactory. It would expose a list of needed parameters whose values can be set. This list in turn can be used by the View to automatically present the user with an input form to enter a value for each parameter, because only the user knows the values of for the parameters.
The call to Create would then use these parameters:
public interface ITradingApiFactory
{
ITradingApi Create();
IEnumerable<Parameter> Parameters { get; }
}
public class Parameter
{
public Parameter(Type type, string name, string description)
{ Type = type; Name = name; Description = description; }
public Type Type { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public object Value { get; set; }
}
public class MT4TradingApiFactory : ITradingApiFactory
{
Dictionary<string, Parameter> _parameters;
public MT4TradingApiFactory()
{ /* init _parameters */ }
public ITradingApi Create()
{
return new MT4TradingApi(_parameters["hostname"].ToString(),
(int)_parameters["port"]);
}
IEnumerable<Parameter> Parameters { get { return _parameters.Values; } }
}
More info can be found in this answer.
This can be advanced further to make it easier to use, by giving each Factory implementation the parameters as properties and change the Parameter class to work directly on these properties using expression trees. If someone is interested in this advanced factory design, please leave a comment.
I think there is nothing wrong with your provider approach. You have two concerns here:
An operational one: your ITradingAPI which defines a contract for operations you can perform.
A meta-data one: something which describes properties of an actual implementation (meta data might not be quiet right but can't think of a better name for it)
Now apparently you need something which can make the connection between the two and that is your ITradingAPIProvider. Seems reasonable straight forward and has good chance of that you will still understand your code when coming back to it after a year ot two ;)
How about trying something similar to the strategy pattern? Create a new interface called IConnectStrategy:
interface IConnectStrategy
{
void Connect();
}
Add the connectstrategy as an argument to the method void CreateOrder(IConnectStrategy connectStrategy) in ITradingApi and let each vendor create/specify their own method for connecting. E.g. for one vendor create:
public class TCPConnectStrategy : IConnectStrategy
{
public TCPConnectStrategy(string hostName, int port)
{
/* ... */
}
public void Connect()
{
/* ... tcp connect ... */
}
}
(Connect might not be the best name or even what you are actually doing, but please apply it to whatever works for your project.)
Edit after comments:
Create a strategy that only have contracts for each method that have vendor-specific parameters. Then add a method void SetVendorStrategy(IVendorStrategy vendorStrategy) (or a property) to the ITradingAPI-interface. Each implementation of the strategy has their own constructor with their own parameters, and each method (that require vendor specific parameters) in each implementation of the ITradingAPI-interface simply calls vendorStrategy.DoSomethingWithVendorSpecificData().

Categories

Resources