Unity.Resolve for a class with a dependency injection - c#

I am using Unity to control Dependency Injection in my Xamarin Forms application. I have a view model class that takes a parent id and a unity injected service as constructor parameters.
public class BrowseViewModel {
public BrowseViewModel(int parentId, IInjectedService injectedService) {
}
}
I have registered the class in the unity container.
unityContainer.registerType<BrowseViewModel>();
I have also registered the service in the unity container.
unityContainer.registerType<IInjectedService, InjectedService>();
My question is, how do I specify the value for parentId when Unity creates an instance of my class? I don't think I should have to specify the injectedService parameter because I have already registered this class with unity and it is a singleton class.

You have a couple of options. You can register your BrowserViewModel like this:
unityContainer.RegisterType<BrowseViewModel>(new InjectionFactory(c => new BrowseViewModel(1234, c.Resolve<IInjectedService>())));
But this way you have a fixed value for parentId (1234 in this example).
You could also use a factory design pattern like so:
public class BrowseViewModelFactory
{
private IInjectedService _injectedService;
public BrowseViewModelFactory(IInjectedService injectedService)
{
_injectedService = injectedService;
}
public BrowseViewModel CreateBrowseViewModel(int parentId)
{
return new BrowseViewModel(parentId, _injectedService);
}
}
Then you inject the BrowseViewModelFactory in class you need the BrowseViewModel and call the create method with the correct parentId. Like:
public class SomeOtherClass
{
private BrowseViewModelFactory _browseViewModelFactory;
public SomeOtherClass(BrowseViewModelFactory browseViewModelFactory)
{
_browseViewModelFactory = browseViewModelFactory;
}
public void DoStuff()
{
var browseViewModel = _browseViewModelFactory.CreateBrowseViewModel(4321);
}
}

You need to register BrowseViewModel like that:
container.RegisterType<Func<int, BrowseViewModel>>(
new InjectionFactory(c =>
new Func<int, BrowseViewModel>(id=> c.Resolve<BrowseViewModel>(new ParameterOverrides { { "parentId", id},))));
Then in contrutor where you use BrowseViewModel, you need to use Func<int, BrowseViewModel> browseViewMdoelFactory
and use it like that:
class SomeViewClass
{
SomeViewClass(Func<int, BrowseViewModel> browseViewMdoelFactory)
{
browsceViewModelFactory(parentId);
}
}

Additionally, you can set the parentId when you try to resolve BrowserViewModel.
At first, just register type:
container.RegisterType<BrowseViewModel>();
// Mark that InjectedService is the singleton using ContainerControlledLifetimeManager
container.RegisterType<IInjectedService, InjectedService>(new ContainerControlledLifetimeManager());
And then resolve type. For this you need to override all primitive types in constructor when try to resolve a type, so you can use ParameterOverrides as pointed out in the answer by #Crekate or can directly put params ParameterOverride as in the code below:
var vm = container.Resolve<BrowseViewModel>(new ParameterOverride("parentId", 546));

Related

Having some parameters Injected with DI and some assigned manually

In a .NET Core 3.1 console application I want a Class that would have some parameters in constructor injected but some that I could assign manually. For example something like that but with IConfiguration Injected:
static void Main() {
var myObj1 = new MyClass(1);
var myObj2 = new MyClass(2);
}
public class MyClass {
public MyClass(IConfiguraiton config, int myVal)
{
}
}
I tried this with Ninject:
static void Main()
{
kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Get<MyClass>();
}
public class MyClass
{
public MyClass(IConfiguraiton config)
{
}
}
public class Bindings : NinjectModule
{
public override void Load()
{
var configuration = new ConfigurationBuilder().AddJsonFile($"appsettings.json").Build();
Bind<IConfiguration>().ToMethod(ctx => SetupConfiguration()).InSingletonScope();
Bind<MyClass>().ToSelf().InTransientScope();
}
}
I managed to make simple dependency injection, but haven't had any success making injection with parameters.
I've read a lot of people suggesting that it's better to pass parameters into methods of the class rather than constructor, however in my situation this isn't an option in addition I'm a software engineering student, and would like to learn how to do this, since it might be useful in some situations.
This is a situation where the Ninject.Extensions.Factory is useful, as it is made exactly for this situation. It does pull in the Factory dependency in addition to Castle.Core, as it uses DynamicProxy under the hood (as a SE student, playing with this library is a good idea for using the interceptor pattern).
To use it, you define a Factory interface like so:
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
Note that the Create method returns MyClass, and the argument(s) to the Create method match exactly in type and name to the arguments you wish to provide. The argument type(s) you want injected must be registered with the kernel. Unfortunately, it is easy to make a mistake here - if you specify a parameter that does not exist in the factory interface it is ignored, but if you forget one it will throw an exception when called.
Next, register IMyClassFactory like this: Bind<IMyClassFactory>().ToFactory(); and remove your binding for MyClass. Then wherever you need to create an instance, inject IMyClassFactory and call Create: kernel.Get<IMyClassFactory>().Create(2)
You can achieve the same result without using Ninject.Extensions.Factory by writing and registering your own implementation of IMyClassFactory, essentially doing the same thing that the code the Factory extension ends up emitting. A full sample is below using both methods based on commenting in/out the registration (note the output if you add .InSingletonScope() to the registration of IConfiguraiton - both approaches respect the binding scopes of Ninject).
internal class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Bind<IConfiguraiton>().To<Configuraiton>();
kernel.Bind<IMyClassFactory>().ToFactory();
//kernel.Bind<IMyClassFactory>().To<NinjectMyClassFactory>().InSingletonScope();
var factory = kernel.Get<IMyClassFactory>();
var one = factory.Create(1);
var two = factory.Create(2);
}
}
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
public class NinjectMyClassFactory : IMyClassFactory
{
public NinjectMyClassFactory(IResolutionRoot resolutionRoot)
{
ResolutionRoot = resolutionRoot;
}
private IResolutionRoot ResolutionRoot { get; }
public MyClass Create(int myVal)
{
return ResolutionRoot.Get<MyClass>(new ConstructorArgument("myVal", myVal));
}
}
public class MyClass
{
public MyClass(IConfiguraiton config, int myVal)
{
Console.Out.WriteLine("Created MyClass({0},{1})", config.MyNum, myVal);
}
}
public interface IConfiguraiton { int MyNum { get; } }
public class Configuraiton : IConfiguraiton
{
static int CreateCount;
public Configuraiton()
{
MyNum = Interlocked.Increment(ref CreateCount);
}
public int MyNum { get; }
}

Ninject - Bind different interfaces implementations to the same class

I'm new to DI (using Ninject) and just started to learn the concepts, but I've been scratching my head for a while to understand this:
Suppose I have DIFFERENT usage of the same class in my program (ProcessContext in the example below).
In the first class (SomeClass) : I would like to inject Implement1 to ProcessContext instance.
In the second class (SomeOtherClass) : I would like to inject Implement2 to ProcessContext instance.
How should I perform the bindings using Ninject ?
public class Implement1 : IAmInterace
{
public void Method()
{
}
}
public class Implement2 : IAmInterace
{
public void Method()
{
}
}
public class ProcessContext : IProcessContext
{
IAmInterface iamInterface;
public ProcessContext(IAmInterface iamInterface)
{
this.iamInterface = iamInterface;
}
}
public class SomeClass : ISomeClass
{
public void SomeMethod()
{
// HERE I WANT TO USE: processcontext instance with Implement1
IProcessContext pc = kernel.Get<IProcessContext>();
}
}
public class SomeOtherClass : ISomeOtherClass
{
public void SomeMethod()
{
// HERE I WANT TO USE: processcontext instance with Implement2
IProcessContext pc = kernel.Get<IProcessContext>();
}
}
You could use named bindings for this.
e.g. something like:
Bind<IProcessContext>()
.To<ProcessContext>()
.WithConstructorArgument("iamInterface", context => Kernel.Get<Implement1>())
.Named("Imp1");
Bind<IProcessContext>()
.To<ProcessContext>()
.WithConstructorArgument("iamInterface", context => Kernel.Get<Implement2>())
.Named("Imp2");
kernel.Get<IProcessContext>("Imp1");
You can inject additional constructor parameters easily in this way:
public void SomeMethod()
{
var foo = new Ninject.Parameters.ConstructorArgument("iamInterface", new Implement2());
IProcessContext pc = kernel.Get<IProcessContext>(foo);
}
For now, I don't have access to ninject. So tell me if it doesn't work as expected.
This is not possible as Ninject has no way of knowing which implementation to return. However; if you create a new instance of your IProcessContext by passing in a variable then Ninject will look for the implementation with the appropriate constructor and return that one.

How can I create instance Dynamically with parameter constructor resolve using autofac DI

my code look like this
private void installData()
{
var dataInstallServices = new List<IDataInstallationService>();
var dataInstallServiceTypes=_typeFinder.FindClassesOfType<IDataInstallationService>();
foreach (var dataInstallServiceType in dataInstallServiceTypes)
dataInstallServices.Add((IDataInstallationService)Activator.CreateInstance(dataInstallServiceType));
foreach (var installServie in dataInstallServices)
installServie.InstallData();
}
my problem is
dataInstallServices.Add((IDataInstallationService)Activator.CreateInstance(dataInstallServiceType,"parameters resolve using autofac"))
I register all dependency but I am getting No parameterless constructor defined for this object. Exception
If you are using AutoFac you shouldn't need to use Activator to create instances.
Say what you are trying to do above lives in a class called DataService that has the following dependencies:
public class DataInstallerA : IDataInstaller {
public DataInstallerA(SubDependencyA a){}
}
public class DataInstallerB : IDataInstaller {
public DataInstallerA(SubDependencyB b){}
}
With the following AutoFac registrations:
builder.RegisterType<SubDependencyA>();
builder.RegisterType<SubDependencyB>();
builder.RegisterType<DataInstallerA>().As<IDataInstaller>();
builder.RegisterType<DataInstallerA>().As<IDataInstaller>();
builder.RegisterType<DataService>();
Your DataService could then look like:
public class DataService
{
private IEnumerable<IDataInstaller> _dataInstallers;
public DataService(IEnumerable<IDataInstaller> dataInstallers) {
_dataInstallers = dataInstallers;
}
public void Install() {
foreach (var installer in _dataInstallers)
installer.InstallData();
}
}
The DataService isn't concerned with having to know how to create all of the IDataInstaller instances, AutoFac can do that, it just needs a collection of them.
Note that even though you didn't actually register the IEnumerable<IDataInstaller> AutoFac provides some extra registrations implicitly when you register a type. See http://autofac.readthedocs.org/en/latest/resolve/relationships.html.
While using Activator.CreateInstance(Type t) method you should make sure the type has parameterless consturctor available to type you are passing to its parametere otherwise it is gonna throw an exception that you got.
Why default consturctor is not there?
When you specify constructor with parameter in class default constructor is removed by compiler.
using System;
public class Program
{
public static void Main()
{
Test t = new Test() //will give you compile time error.
Test t1 = new Test(""); //should work fine.
}
}
public class Test
{
public Test(string a)
{
}
}
Use another overloaded method to pass constructor params there like below:
Activator.CreateInstance(typeof(T), param1, param2);
MSDN documentation for that method is here.

Autofac delegate factories, and passing around container

I have a question about delegate factories: autofac docs
I understand how they set up the factories but I do not get the resolving part:
var shareholdingFactory = container.Resolve<Shareholding.Factory>();
var shareholding = shareholdingFactory.Invoke("ABC", 1234);
It looks like you have to pass around the container in order to resolve. Maybe I have to Invoke something with parameters I only know at runtime. How do I do that without passing the container to for example a service method?
UPDATE
So you are supposed to pass the factories instead?
Autofac can automatically resolve factories, i.e. without the container:
public class ShareHolding
{
public ShareHolding(int accountId)
{
// do whatever you want
}
}
public class MyApp
{
private readonly ShareHolding _shareHolding;
public MyApp(Func<int, ShareHolding> shareHoldingFactory)
{
_shareHolding = shareHoldingFactory(99);
}
public void Run()
{
// do whatever you want with the _shareHolding object
}
}
Autofac registration
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ShareHolding>(); // not a singleton
containerBuilder.RegisterType<MyApp>().SingeInstance();
var myApp = containerBuilder.Resolve<MyApp>();
myApp.Run();
Now, if your ShareHolding type had ctor like:
public class ShareHolding
{
public delegate ShareHolding Factory(int accountId, int userId);
public ShareHolding(int accountId, int userId)
{
// do whatever you want
}
}
Then you would need a delegate factory because Autofac resolves constructors using type information and delegate factories using parameters names. Your usage would then become:
public class MyApp
{
public MyApp(ShareHolding.Factory shareHoldingFactory)
{
....
}
}

Configuring an Autofac delegate factory that's defined on an abstract class

I'm working on a C# project. I'm trying to get rid of a Factory class that has a large switch statement.
I want to configure Autofac to be able to construct a dependency based on a parameter, thereby allowing Autofac to take the place of the Factory.
I've looked at the DelegateFactories page of the Autofac wiki, but I can't figure out how to apply the pattern to an abstract class. Here's some code showing the situation:
public enum WidgetType
{
Sprocket,
Whizbang
}
public class SprocketWidget : Widget
{
}
public class WhizbangWidget : Widget
{
}
public abstract class Widget
{
public delegate Widget Factory(WidgetType widgetType);
}
public class WidgetWrangler
{
public Widget Widget { get; private set; }
public WidgetWrangler(IComponentContext context, WidgetType widgetType)
{
var widgetFactory = context.Resolve<Widget.Factory>();
Widget = widgetFactory(widgetType);
}
}
I'd like it if I were to say new WidgetWrangler(context, WidgetType.Sprocket), its Widget property would be a SpocketWidget.
When I try this, I get errors stating that Widget.Factory is not registered. Does this delegate factory pattern not work with abstract classes, and if so, is there another way to accomplish this?
What you're looking for is the IIndex<,> Relationship Type.
If you register your sub-classes with .Keyed<>(...) you can key a registration to a value (object).
For example:
builder.RegisterType<SprocketWidget>()
.Keyed<Widget>(WidgetType.Sproket)
.InstancePerDependency();
builder.RegisterType<WhizbangWidget>()
.Keyed<Widget>(WidgetType.Whizbang)
.InstancePerDependency();
Then you only require a dependency of IIndex<WidgetType,Widget> to mimic factory behaviour.
public class SomethingThatUsesWidgets
{
private readonly IIndex<WidgetType,Widget> _widgetFactory;
public SomethingThatUsesWidgets(IIndex<WidgetType,Widget> widgetFactory)
{
if (widgetFactory == null) throw ArgumentNullException("widgetFactory");
_widgetFactory = widgetFactory;
}
public void DoSomething()
{
// Simple usage:
Widget widget = widgetFactory[WidgetType.Whizbang];
// Safe Usage:
Widget widget2 = null;
if(widgetFactory.TryGetValue(WidgetType.Sprocket, out widget2))
{
// do stuff
}
}
}
That's using Dependency Injection approach, if you just want to resolve the factory:
var factory = Container.Resolve<IIndex<WidgetType,Widget>>();

Categories

Resources