Error when creating DependencyInjectionContainer
Closed this issue · 7 comments
I am trying to evaluate your project to add to my list of RSCG https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples
However, I am getting an error message
1>D:\gth\RSCG_Examples\v2\rscg_examples\FactoryGenerator\src\InjectDemo\Program.cs(3,56,3,61): error CS7036: There is no argument given that corresponds to the required parameter 'con' of 'DependencyInjectionContainer.DependencyInjectionContainer(DatabaseCon)'
Attached the project for your convenience
InjectDemo.zip
Any unsatisfied dependency "bubbles up" as a constructor parameter of the container. It basically means that if FactoryGenerator cannot find any implementation of a referenced interface, it requires you to supply an instance outside of the lifetime scope of the container.
Make sure you have an [Inject] anywhere on the implementation of the interface you are trying to use in a dependency.
In a regular non generated container (Autofac, Ninject, ASP.NET's built in, etc.), this compilation error would be a runtime exception.
I think what you have going on is this:
[Inject]
class Foo : IFoo {
public Foo(IBar bar) { ... }
}
// Missing [Inject]
class Bar : IBar { ... }
Since FactoryGenerator cannot deduce how IBar
is to be instantiated, it relegates that to the owner of the container.
Did you try the project attached ? I think I have put
[Inject]
everywhere it is needed
Hello!
From the looks of it you have two classes, Database & DatabaseCon that both implement IDatabase. You then [Inject] both of these which will register then into the container as IDatabase. The Database class then takes on a dependency on DatabaseCon (the specific implementation, not the interface) through it's constructor.
If you want DatabaseCon to be explicitly available as resolvable from the container, and not just to be resolvable as IDatabase, consider adding the [Self] attribute to DatabaseCon.
both classes have
[Inject,Scoped]
public partial class DatabaseCon: IDatabase{
}
[Inject, Scoped]
public partial class Database : IDatabase{
}
The problem is that , when compiling , this is giving an error on program.cs
InjectDemo.Generated.DependencyInjectionContainer sc = new();
That's because this is generated :
public partial class DependencyInjectionContainer
{
InjectDemo.DatabaseCon con;
public DependencyInjectionContainer(InjectDemo.DatabaseCon con)
{
( When you download the previous example, please add partial declaration to class Database )
That is correct, you have injected the DatabaseCon
& Database
classes as IDatabase
into the container.
Then, when generating your container, the source generator notices that Database
has a constructor that takes a DatabaseCon
instance, not an IDatabase
instance. As such, since the only thing that has been provided to the container are two instances of IDatabase
, as per the behavior of the [Inject] attribute in readme.md, the container has nothing to provide that constructor, and as such, bubbles it up to the generated constructor of the container itself.
In order to work around this, you could either:
A:
Add the [Self]
Attribute to DatabaseCon
as per, a suggestion would be to add the [ExceptAs<IDatabase>]
attribute as well, since your intent seems to be to Resolve the Database
class as the sole implementer of IDatabase
, and in that scenario you would not want to expose both as IDatabase
to the container
[Inject, Scoped, Self, ExceptAs<IDatabase>]
public partial class DatabaseCon: IDatabase{
}
This will specify to the container that it is to provide this specific implementation of the class interfaces as something directly resolvable from the container. As a DatabaseCon
is available to the container now, it will be provided to the constructor of Database
and will no longer be generated as part of the container constructor.
B:
Construct Database using an IDatabase instance, rather than the specific implementation DatabaseCon
. For clarity´s sake as well, you would want to make sure that DatabaseCon
is not implementing the exact same interface as Database
. Since it has a property "Connection" that we are interested in, let´s extract that into another interface
public interface IConnection : IDatabase
{
string? Connection { get; set; }
}
And switch DatabaseCon
over to implementing that interface instead, as per
[Inject,Scoped]
public partial class DatabaseCon: IConnection
{
public string? Connection { get; set; }
public void Open()
{
Console.WriteLine("open" + Connection);
}
}
no actual code modification beyond changing the interface is nessecary.
Then, we edit the Database
class to take an IConnection
instead of a specific DatabaseCon
implementation as follows:
[Inject, Scoped]
public class Database : IDatabase
{
private readonly IConnection con;
public Database(IConnection con)
{
this.con = con;
}
/* Rest of the code */
}
Then the container will no longer need a constructor parameter, since IConnection
is exposed to the container via DatabaseCon
[Inject] attribute.
You are right!
I have put [Self] and all it is ok now
Thanks!
https://ignatandrei.github.io/RSCG_Examples/v2/docs/FactoryGenerator