I'm trying to refactor some code to use IoC with the Ninject framework. So far I have managed to successfully inject in classes in scenarios where I do not have any constructor parameters to pass. However I am having difficulties when it comes to passing in parameters. This is the third binding in the binding class below.
Binding Class
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<Logger>();
Bind<IPlayerDatadao>().To<PlayerDatadao>();
Bind<IPlayerScores>().To<PlayerScores>();
}
}
The logger class has a parameterless constructor and works fine when transferred to Ninject.
Success
// IoC creation
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
//Log User details
var logger = kernel.Get<ILogger>();
logger.LogVisitorDetails();
However, my attempt below threw an exception
Failure
string priceString = Foo();
string pointsString = Bar();
return kernel.Get<IPlayerScores>(new[] { new ConstructorArgument("pointsString", pointsString), new ConstructorArgument("points", priceString) });
This is the class with its constructor.
Class to Inject
public class PlayerScores : IPlayerScores
{
[Inject]
public string points { get; set; }
[Inject]
public string price { get; set; }
public PlayerScores(string Points, string Price)
{
points = Points;
price = Price;
}
}
I'm really not sure how I should be handling the parameters either in the binding class or at the point of injection
I'm really not sure how I should be handling the parameters either in the binding class or at the point of injection
At binding. You should remove any Ninject dependencies from your model:
public class PlayerScores : IPlayerScores
{
public PlayerScores(string points, string price)
{
this.Points = points;
this.Price = price;
}
public string Points { get; set; }
public string Price { get; set; }
}
and then configure the kernel:
Bind<IPlayerScores>()
.To<PlayerScores>()
.WithConstructorArgument("points", "some points")
.WithConstructorArgument("price", "some price");
or using ToMethod which is a bit more refactor friendly as it avoids the magic strings with the parameter names:
Bind<IPlayerScores>()
.ToMethod(ctx => new PlayerScores("some points", "some price"));
This being said, if the 2 parameters are so volatile that they need to have a different value on each call, then you probably should not be passing them as constructor parameters but rather as parameters to some instance method that you would invoke on the class at runtime.
Related
So I have this data class:
public class RecentProject
{
public string ProjectName { get; set; }
public string ProjectPath { get; set; }
public DateTime CreationDate { get; set; }
public string OutputFolder { set; get; } = "";
}
It just defines the properties of the recent project, and I wanted to apply dependency inversion so I extracted an interface from the class:
public interface IRecentProject
{
DateTime CreationDate { get; set; }
string OutputFolder { get; set; }
string ProjectName { get; set; }
string ProjectPath { get; set; }
}
then I made an ioc container(inversion of control) and registered the class type as the interface:
Mvx.IoCProvider.RegisterType<IRecentProject, RecentProject>();
so anywhere in my app when I want to create a recent project I just use:
Mvx.IoCProvider.Resolve<IRecentProject>();
but after I did this I ran into some problems that would be hard to solve with the current setup so I thought that maybe this is not the correct way to apply dependency inversion in this class because none of the dependency inversion benefits would apply like:
unit testing: as I will not be unit testing a data class
The ability to change the class implementation: as any changes in the class will require a change in the interface to be able to use the new features added
So what should I do, I have searched a lot on this topic and could not find a clear answer,
please help and thanks in advance.
If RecentProject is a pure data class, that is it contains no logic, then indeed no need either for unit testing or for abstraction. And of course, IoC is out of scope here.
Things look different when logic and polymorphism are involved. You may want, for example, to have two types of projects with each implementing name validation in its own (simplistic) way:
public class RecentCSharpProject : IRecentProject
{
.
.
.
public string ProjectName
{
get => this.projectName;
set
{
if (!value.EndsWith("csproj"))
{
throw (new Exception("This is not a C# project"));
}
this.projectName = value;
}
}
}
public class RecentFSharpProject : IRecentProject
{
.
.
.
public string ProjectName
{
get => this.projectName;
set
{
if (!value.EndsWith("fsproj"))
{
throw (new Exception("This is not an F# project"));
}
this.projectName = value;
}
}
}
You may still choose to skip unit tests, plus IoC still irrelevant (services are to be injected, not data models).
However, you will now be able to instantiate appropriate class while still "speaking" the interface language to the outside world:
public IRecentProject AddProjectToFileMenu(string projectName, bool isFSharp)
{
IRecentProject project = (isFSharp ? new RecentFSharpProject() : new RecentCSharpProject());
project.ProjectName = projectName; // Internally validate extension according to concrete class
// TODO: add project to file-menu
return (project);
}
I'm building a password generator. I'm trying to apply the Dependency Inversion Principle (DIP) but so far my solution still seems to be coupled with concrete data.
How do I decouple the PasswordGenerator? So I don't have to pass to it
new PasswordRequirementsRepository(new PasswordRequirements{[properties assigned here]})
and I can inject an interface instead which will be used by IoC Container?
How can I pass in the data assigned to PasswordRequirements properties to the PasswordGenerator without creating an instance of PasswordRequirementsRepository?
I'm struggling when passing different sets of password requirements because in PasswordGenerator I have to pass a concrete instance of PasswordRequirementsRepository instead of interface. I guess what I'm trying to achieve is to decouple PasswordGenerator from the concrete set of password requirements.
IPasswordRequirementsRepository.cs
public interface IPasswordRequirementsRepository
{
PasswordRequirements GetPasswordRequirements();
}
PasswordRequirementsRepository.cs
public class PasswordRequirementsRepository : IPasswordRequirementsRepository
{
private readonly PasswordRequirements _requirements;
public PasswordRequirementsRepository(PasswordRequirements requirements)
{
_requirements = requirements;
}
public PasswordRequirements GetPasswordRequirements()
{
return _requirements;
}
}
IPasswordGenerator.cs
public interface IPasswordGenerator
{
string GeneratePassword();
}
PasswordGenerator.cs
public class PasswordGenerator : IPasswordGenerator
{
private readonly IPasswordRequirementsRepository _repository;
public PasswordGenerator(IPasswordRequirementsRepository repository)
{
_repository = repository;
}
public string GeneratePassword()
{
PasswordRequirements requirements = _repository.GetPasswordRequirements();
[password generation logic here]
}
}
PasswordRequirements.cs
public class PasswordRequirements
{
public int MaxLength { get; set; }
public int NoUpper { get; set; }
public int NoLower { get; set; }
public int NoNumeric { get; set; }
public int NoSpecial { get; set; }
}
How do I decouple the PasswordGenerator? So I don't have to pass to it and I can inject an interface instead which will be used by IoC Container?
1st - Derive an interface:
public class IPasswordRequirements
{
int MaxLength { get; }
int NoUpper { get; }
int NoLower { get; }
int NoNumeric { get; }
int NoSpecial { get; }
}
2nd - Inherit from interface:
public class PasswordRequirements : IPasswordRequirements
{
public int MaxLength { get; set; }
public int NoUpper { get; set; }
public int NoLower { get; set; }
public int NoNumeric { get; set; }
public int NoSpecial { get; set; }
}
3rd - Update constructor:
public class PasswordGenerator : IPasswordGenerator
{
public PasswordGenerator(IPasswordRequirements passwordRequirements)
{
}
That's it.
Don't use a repository here
My fear is that your understanding of a repository and DI infer some time of requirement to always be used together. What I believe your lacking is the code that instantiates dependencies. While a repository may at it's core provide that as a bases of it's pattern, it isn't the correct choice here, because of two reasons; first you aren't storing the items in the repository (that is there is no tier virtual or physical abstraction to wrap the repository around) and secondly you aren't providing generic access to a wide variety of types, just a single one.
At it's core the only thing a repository needs to be useful is a configuration/object to pass objects.. to some other tier (SQL, File system, Web API). A repository is not required in all instances to know anything about how objects are created.
Choose a framework that fits your need
Instead, what you need is a framework built at it's core around DI; object creation and disposal, and having an interface/configuration in which to configure the framework so it can be aware of dependencies to assist in the creation of dependent objects. There are three that come to mind AutoFac, Ninject and Unity. In each of these case, you are in some way, required to configure each type and use it's pattern to create objects. In many cases these Frameworks can even be full featured replacements with other Microsoft Frameworks (MVC for example, has it's own way to instantiate objects, but can be replace with other DI Frameworks). In no way are these frameworks required to know configuration on how to pass these objects to other tiers. It may do so simply by configuration as a by-product, but at it's core that's not what is configured.
For example with Autofac, first you create builder which is basically a fancy way to create a configuration:
var builder = new ContainerBuilder()
Then you register your types:
builder.RegisterType<PasswordRequirements>.As<IPasswordRequirements>();
Create a Container which manages objects: from their instantiation to their configuration.
var container = builder.Build();
Create a scope which defines the duration of an objects lifetime.
using (var scope = new BeginLifetimeScope())
{
// all objects created by scope which be disposed when the scope is diposed.
var passwordRequirements = scope.Resolve<IPasswordRequirements>();
}
By default passwordRequirements will be a new PasswordRequirements(). From there you simply build out your necessary dependency requirements and let the framework handle the rest.
Crux of the issue related to Dependency Inversion
On creating the instance of the PasswordGenerator. which inject, IPasswordRequirementsRepository, in current design there's a limitation of passing the concrete instance of PasswordRequirements, which shall be avoided for true Dependency inversion design.
Following are the possible solutions:
Create an interface or preferably an abstract class for the PasswordRequirements, which can be overridden and can be injected on the need basis, which will be automatically injected when IPasswordRequirementsRepository is injected in the PasswordGenerator
Let's consider the abstract class:
public abstract class BasePasswordRequirements
{
public abstract int MaxLength { get; set; }
public abstract int NoUpper { get; set; }
public abstract int NoLower { get; set; }
public abstract int NoNumeric { get; set; }
public abstract int NoSpecial { get; set; }
}
public class PasswordRequirements : BasePasswordRequirements
{
public override int MaxLength { get; set; }
public override int NoUpper { get; set; }
public override int NoLower { get; set; }
public override int NoNumeric { get; set; }
public override int NoSpecial { get; set; }
}
Using Ninject DI container Binding would be as follows, along with named binding:
Kernel.Bind<IPasswordRequirementsRepository>().To<PasswordRequirementsRepository>()
Kernel.Bind<BasePasswordRequirements>().To<PasswordRequirements>()
PasswordRequirementsRepository will be as follows:
public class PasswordRequirementsRepository : IPasswordRequirementsRepository
{
private readonly BasePasswordRequirements Requirements{get;}
public PasswordRequirementsRepository(BasePasswordRequirements requirements)
{
Requirements = requirements;
}
public BasePasswordRequirements GetPasswordRequirements()
{
return Requirements;
}
}
Another option would be constructor Injection, in that case PasswordRequirements, may not need a Base class or interface, in that case binding would be like:
Kernel.Bind<IPasswordRequirementsRepository>().To<PasswordRequirementsRepository>()
.WithConstructorArgument("requirements", new
PasswordRequirements { .... });
This would call the correct constructor, with relevant values filled in
You may also consider combination of both approached 1 and 2 , where you create a base class / interface for PasswordRequirements and also constructor injection.
For various versions of PasswordRequirements, that you may want to inject consider named binding, following shall be example, instead of:
public class PasswordRequirementsRepository : IPasswordRequirementsRepository
{
private readonly Func<string,BasePasswordRequirements> RequirementsFunc{get;}
public PasswordRequirementsRepository(Func<string,BasePasswordRequirements> requirementsFunc)
{
RequirementsFunc = requirementsFunc;
}
public BasePasswordRequirements GetPasswordRequirements(string name="Version1")
{
return requirementsFunc(name);
}
}
Ninject Binding would be as follows
Kernel.Bind<Func<string,BasePasswordRequirements>>()
.ToMethod(context => name => context.Kernel
.Get<BasePasswordRequirements>(name);
);
Bind<BasePasswordRequirements>().To<PasswordRequirements>().Named("Version1");
Bind<BasePasswordRequirements>().To<AnotherPasswordRequirements>().Named("Version2");
Here the Name for Binding can be passed at the run-time to tweak object that will be injected and thus change the behavior by run-time, thus achieving dependency inversion by using a DI framework like Ninject, which lot of flexible options
Based on the code snippet in your question, the implementation of PasswordGenerator is decoupled from the implementation of the IPasswordRequirementsRepository as it is the interface that is given as constructor argument and not a specific implementation.
To decouple the PasswordRequirementsRepository from a specific implementation of the PasswordRequirements you can do one of two things.
Introduce an interface IPasswordRequirements.
Make PasswordRequirements abstract.
Either approach will decouple the implementation of PasswordRequirementsRepository from the implementation of PasswordRequirements.
DI container
How do I decouple the PasswordGenerator? So I don't have to pass to it
new PasswordRequirementsRepository(new PasswordRequirements{[properties assigned here]})
and I can inject an interface instead which will be used by IoC Container? How can I pass in the data assigned to PasswordRequirements properties to the PasswordGenerator without creating an instance of PasswordRequirementsRepository?
I believe that this part of the question builds on a misunderstanding of the role of the DI container. When building your container you will register all the Classes/Interfaces that is needed in your system. This could look something like the following:
Register<IPasswordRequirements>().To<PasswordRequirements>();
Register<IPasswordRequirementsRepository>().To<PasswordRequirementsRepository>();
Register<IPasswordGenerator>().To<PasswordGenerator>();
After registering everything you can ask the container to provide you with an instance of an interface. In your case, this would be an instance of IPasswordGenerator. The request typically looks a something like this:
var passwordGenerator = contain.Resolve<IPasswordGenerator>();
Normally you only request the topmost component of your program, as the DI container knows what is needed to instantiate every class the component depends on. You would not create a new instance of PasswordGenerator by manually resolving the dependencies and the inject these into the constructor. This approach counteracts the purpose of the DI container.
One option might be to use generics to abstract out the different types of password requirements you might use, and pass the options through the GeneratePassword method since that's really a parameter to how you generate the password. I.E.
interface IPasswordGenerator<TPasswordRequirements>
{
string GeneratePassword(TPasswordRequirements reqs);
}
interface IPasswordRequirementRepository<TPasswordRequirements>
{
TPasswordRequirements GetPasswordRequirements();
}
Implemented by
class DefaultPasswordReqs
{
public int MaxLength { get; set; }
// ...
}
class DefaultPasswordGenerator : IPasswordGenerator<DefaultPasswordReqs>
{
public string GeneratePassword(DefaultPasswordReqs reqs)
{
// ... logic specific to DefaultPasswordReqs
}
}
class InMemoryPasswordRequiremntsRepository<TPasswordRequirements> :
IPasswordRequirementRepository<TPasswordRequirements>
{
private readonly TPasswordRequirements _reqs;
public InMemoryPasswordRequiremntsRepository(TPasswordRequirements reqs)
{
_reqs = reqs;
}
public TPasswordRequirements GetPasswordRequirements()
{
return _reqs;
}
}
And then in whatever code depends on the password generator, have it take a dependency which has the specifc type of password requirements it will use and read the requirements and use those requirements to generate the password.
var requirements = _passwordRequiremntsRepository.GetPasswordRequirements();
var password = _passwordGenerator.GeneratePassword(requirements);
I have a class named SomeRule that can be serialized in a XML format. The class uses an ISomeService that I would like to be injected via autofac.
[Serializable]
public class SomeRule
{
[XmlAttribute("Attribute1")]
public string Attribute1 {get;set;}
[XmlAttribute("Attribute2")]
public string Attribute2 { get; set; }
private readonly ISomeService m_someService;
private SomeRule() { }
public SomeRule(ISomeService someService)
{
m_someService = someService;
}
public void DoSomething()
{
m_someService.DoStuff(Attribute1);
}
}
public interface ISomeService {
void DoStuff(string param);
}
public class SomeServiceImpl : ISomeService
{
public void DoStuff(string param) => // Do something with the stuff.
}
Now, my program receives an XML string that I would like to deserialize but also, at the same time, have autofac inject the dependency for me.
void Main()
{
string serializedRule =
"<?xml version=\"1.0\" encoding=\"utf-16\"?>" +
"<SomeRule xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"Attribute1=\"Huuuuuge\" " +
"Attribute2=\"Cofveve\" />";
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SomeRule));
var stringBuilder = new StringBuilder(serializedRule);
var newRule = xmlSerializer.Deserialize(
new StringReader(stringBuilder.ToString())) as SomeRule;
// ISomeService was not injected yet. Is it possible?
}
I can make this work by calling the autofac container, get the registered implementation of the ISomeService interface and assign it to a public property of the SomeRule instance. I am looking for a better solution, one that would not require the class to have a public property.
Is there a way to automatically inject dependencies with XmlSerializer?
From a DI standpoint, having data-centric objects with constructors that accepts service dependencies is rather problematic, and should be prevented.
When practicing DI, we try to centralize the composition of our object graphs of application components (i.e. the classes that contain behavior and have dependencies of their own) to a centralized place in the application called the Composition Root.
A data-centric object that includes constructor dependencies, however, complicates this practice, since it either forces composition out of the Composition Root, or forces the addition of factory abstractions for the creation of these objects.
Instead, you should use one of following two alternatives:
Separate data and behavior. This means moving SomeRule's DoSomething method to a new class, that takes SomeRule as an argument in its public method(s). The constructor dependency will move to this new class as well.
Remove the constructor dependency of SomeRule and instead inject it into DoSomething using method injection.
Option 1 might look like this:
// SomeRule only contains data. Much simpler
[Serializable]
public class SomeRule
{
[XmlAttribute("Attribute1")]
public string Attribute1 {get;set;}
[XmlAttribute("Attribute2")]
public string Attribute2 { get; set; }
}
// Moved behavior to new class. This class can be injected
// into consumers, as usual.
public class SomeRuleHandler : IRuleHandler<SomeRule>
{
private readonly ISomeService m_service;
// There's now just one constructor left
public SomeRuleHandler(ISomeService service)
{
m_service = service ?? throw new ArgumentNullException("service");
}
public void DoSomething(SomeRule rule)
{
m_service.DoStuff(rule.Attribute1);
}
}
With option 2, the result will be the following:
[Serializable]
public class SomeRule
{
[XmlAttribute("Attribute1")]
public string Attribute1 { get; set; }
[XmlAttribute("Attribute2")]
public string Attribute2 { get; set; }
// No more constructors. The dependency is supplied in the method,
// but *not* stored.
public void DoSomething(ISomeService service)
{
service.DoStuff(Attribute1);
}
}
I have such a class
public sealed class SimpleTextIndex<T> : TextIndex where T : ITextParser
{
[Inject]
public T TextParser { get; set; }
// something...
And dependency resolving method
public void Resolve()
{
Kernel = new StandardKernel();
Kernel.Bind(typeof(ITextParser)).To(typeof(WordTextParser));
Kernel.Bind(typeof(SimpleTextIndex<>)).ToSelf();
}
WordTextParser is a class, which implements ITextParser interface.
But, after calling Resolve() method and kernel's Get() method:
var textIndex = kernel.Get<SimpleTextIndex<ITextParser>>();
I'm getting a NullReferenceException (TextParser property in SimpleTextIndex is null)!
But, if I write a default constructor for SimpleTextIndex this way:
public SimpleTextIndex()
{
DependencyResolver.Kernel.Inject(this);
}
Everything works fine! Why?
The problem is that property injection is done only after the object is constructed via the constructor, i.e., Ninject cannot set the property value before the constructor is done.
Since you are using the dependency from a method invoked from the constructor, then the property is not yet set and therefore its value is null.
Either don't use the dependency during construction or use Constructor Injection like this:
//[Inject] //remove this attribute
public T TextParser { get; set; }
public SimpleTextIndex(T parser, string text = "")
{
TextParser = parser;
...
}
I have a simple class with 2 constructors.
The first (default) constructor that takes no parameters constructs all the properties so they are not null once this object is instantiated.
the second constructor that takes an int parameter does a lot more logic, but it also need to do exactly what the default constructor does with regards to setting up the properties.
Is there away I can inherit from this default constructor so im not duplicating code?
code below...
public class AuctionVehicle
{
public tbl_Auction DB_Auction { get; set; }
public tbl_Vehicle DB_Vehicle { get; set; }
public List<String> ImageURLs { get; set; }
public List<tbl_Bid> Bids { get; set; }
public int CurrentPrice { get; set; }
#region Constructors
public AuctionVehicle()
{
DB_Auction = new tbl_Auction();
DB_Vehicle = new tbl_Vehicle();
ImageURLs = new List<string>();
ImageURLs = new List<string>();
}
public AuctionVehicle(int AuctionID)
{
// call the first constructors logic without duplication...
// more logic below...
}
}
You can do it like this:
public AuctionVehicle(int AuctionID) : this()
{
...
}
public AuctionVehicle(int AuctionID) : this()
{
// call the first constructors logic without duplication...
// more logic below...
}
Or factor it out to a private method which contains the common logic.
public AuctionVehicle(int AuctionID)
: this()// call the first constructors logic without duplication...
{
// more logic below...
}
inheritance from constructor is not allowed in c#
Reason :-
If constructor inheritance were allowed, then necessary initialization in a base class constructor might easily be omitted. This could cause serious problems which would be difficult to track down. For example, if a new version of a base class appears with a new constructor, your class would get a new constructor automatically. This could be catastrophic.