-
-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Getting instance from parent scope even if replaced by Use #460
Comments
@phoeniks-sk Hi, thanks for repro tests. |
Ah, I should have mentioned that, I've originally tested it on 4.8.6, but 4.8.7 seems to behave the same. |
You need to plan for the original Data replacement making it dynamic by either registering container.RegisterInstance(new Data { Text = "parent" }, setup: Setup.With(asResolutionCall: true)); or do original registration of Data with Check the tests in my commit 11ec0e8 |
@dadhi Thank you for a quick response. That does work. The problem is however that my real code uses a container So to solve this, I came up with var container = new Container(rules => rules
.WithDynamicRegistrationsAsFallback(
(type, obj) =>
{
if (type == typeof(Data)) // some sort of whitelist here
return new[] { new DynamicRegistration(new ReflectionFactory(type, setup: Setup.With(asResolutionCall: true))) };
return null;
},
Rules.ConcreteTypeDynamicRegistrations())); Now there are two questions:
Thank you. |
Sorry, I did not fully get it. What do you mean by whitelist? If you mean to skip the |
By whitelist I meant the way to determine which classes manifest the behavior described above. There's a comment in the code where the whitelist would go. But for now I just used your first suggestion and registered the "data" classes with However today I ran into another issue. We are using a container The changed test would be: public class Data
{
public string Text { get; set; }
}
public interface IDataDependent
{
Data Data1 { get; }
}
public class DataDependent : IDataDependent
{
public Data Data1 { get; }
public DataDependent(IData data)
{
Data1 = data;
}
}
public class DataDependentIndirectly
{
private Lazy<IDataDependent> _lazyDependent;
public IDataDependent Dependent => _lazyDependent.Value;
public DataDependentIndirectly(Lazy<IDataDependent> dataDependent)
{
_lazyDependent = dataDependent;
}
}
[Fact]
public void Should_use_data_from_the_scope_when_resolving_in_scope()
{
var container = new Container(rules => rules.WithFuncAndLazyWithoutRegistration()));
container.RegisterInstance(new Data { Text = "parent" }, setup: Setup.With(asResolutionCall: true));
container.Register<IDataDependent, DataDependent>();
container.Register<DataDependentIndirectly>();
// now it fails even if this is removed
var outside = container.Resolve<DataDependentIndirectly>();
using var scope = container.OpenScope();
scope.Use(new Data { Text = "child" });
var inScope = scope.Resolve<DataDependentIndirectly>();
Assert.Equal("child", inScope.Dependent.Data1.Text); // fails, the value is "parent"
} Note the The only way how to solve this I found for now is to manually register Lazy: But I cannot possibly register Lazy of all the classes that might have a Am I doing something wrong? From the documentation I would expect that Lazy is in fact just wrapping the resolve call. NB: This fails both with and without NB2: The same problem appears to be with |
@phoeniks-sk Saw this, will check |
@phoeniks-sk Hi, the problem is again with the capturing the resolution context for the dynamic resolution. In this particular case, it is captured to be a root container instead of scope for the |
The v4.8.8 with the fix is out. |
Thank you very much for the quick turnaround, that solved the issues with But the original problem still prevails, here's a simplified example: public class A : IA { }
public class DifferentA : IA { }
public interface IA { }
public class B
{
public IA A { get; }
public B(IA a) { A = a; }
}
[Fact]
public void Should_use_correct_dependency_in_scope()
{
var container = new Container();
container.Register<IA, A>(Reuse.ScopedOrSingleton);
container.Register<B>(Reuse.ScopedOrSingleton);
// test passes if B is not resolved outside the scope
var bSingleton = container.Resolve<B>();
using var scope = container.OpenScope();
var differentA = new DifferentA();
scope.Use<IA>(differentA);
var bScope = scope.Resolve<B>();
Assert.Equal(bScope.A, differentA); // fails, uses the A from the singleton scope
} It works if the Is there something that can be done about that? Edit: Because of the fix in v4.8.8, this problem also doesn't happen if B has dependency on |
The
Yeah, I share your concern. It is hard to solve for the general use-case, preserving the performance. You are either going for the rigid but fast object graph where everything is known beforehand, or you are going with a completely dynamic graph where you can decide in runtime what is the next dependency. I have decided to optimize for the well-known graph with ability to have a dynamic cuts in it via In your situation, it is even more complicated with the dual reuse of Anyway, thanks for the test. I will play with it. I have some broader ideas on how to hijack the graph and substitute the pieces of it for testing. It may be no via var testA = new DifferentA();
var testContainer = container.WithInterpretationOverload(implType => implType switch {
typeof(A) => testA,
_ => null // go the normal route
}); Cons:
Pros:
|
Hello,
maybe I'm doing something wrong. I have the following code:
I would expect the
DataDependentIndirectly
object created in the scope to have the value of theData
that was added usingUse
injected. This happens, but only ifDataDependentIndirectly
is not resolved outside the scope first. Otherwise it gets the value with "parent"Text
created outside the scope.If I resolve
Data
manually from the scope, the value is correct.It also works correctly if using a child container instead of a scope. Am I doing something wrong? It seems to me like this is exact use case for scopes, i.e. injecting some scope-related data into the object tree resolved in the scope.
Thanks for the response in advance.
The text was updated successfully, but these errors were encountered: