Skip to content

Get the name of calling class #264

Closed

Description

@silkfire

How do I get the name / type of the class that's trying to resolve a dependency, let's say via ctor injection? I tried to resolve IInjectionContext and StaticInjectionContext in ExportFactory but neither of the objects contained any useful information.

Activity

  1. ipjohnson commented on Jun 3, 2020

    @ipjohnson
    Owner

    Hmmm you should be able to get it from the StaticInjectionContext . I'm guessing the static context wasn't passed through correctly for the ExportFactory.

    I'll see if I can take a look tonight or tomorrow. I don't think it should be hard to address

  2. silkfire commented on Jun 3, 2020

    @silkfire
    ContributorAuthor

    Thanks! There's an enum value there indicating how the dependency call was made, but it seems to always be set to Root, maybe that's related (should be Constructor Injection or something like that).

  3. ipjohnson commented on Jun 3, 2020

    @ipjohnson
    Owner

    That's what I suspected when the factory is being created it's being rooted and it's not carrying any context information over. That's incorrect and shouldn't be too hard to address.

  4. ipjohnson commented on Jun 6, 2020

    @ipjohnson
    Owner

    So it's not as simple as I originally thought because for simple cases it's working as seen in the test

    What does the registration look like does it have a lifestyle on it? If so that can cause it to be rooted.

  5. silkfire commented on Jun 7, 2020

    @silkfire
    ContributorAuthor

    That's correct, I'm setting a Singleton lifestyle on the registered dependency.

  6. ipjohnson commented on Jun 9, 2020

    @ipjohnson
    Owner

    could you put together a quick sample, I wasn't able to reproduce this but I'm not sure I have it setup the same way you do.

  7. silkfire commented on Jun 9, 2020

    @silkfire
    ContributorAuthor

    You're correct, Ian, it seems to work if I don't specify the Singleton lifestyle. The test below should be sufficient to reproduce this scenario:

    namespace GraceTests
    {
        using Grace.DependencyInjection;
        using Xunit;
    
    
        public class DependencyResolutionTests
        {
            [Fact]
            public void Given_a_dependency_injection_request_from_a_constructor_request_type_should_be_constructor_parameter()
            {
                var container = new DependencyInjectionContainer();
    
                container.Configure(_ =>
                {
                    _.ExportFactory<StaticInjectionContext, DependencyImpl>(ctx =>
                    {
                        Assert.Equal(RequestType.ConstructorParameter, ctx.TargetInfo.InjectionDependencyType);
    
                        return new DependencyImpl();
                    }).As<IDependency>().Lifestyle.Singleton();
                });
    
    
                var service = container.Locate<Service>();
            }
        }
    
    
        internal class Service
        {
            public Service(IDependency dependency) { }
        }
    
        internal interface IDependency {}
    
        internal class DependencyImpl : IDependency { }
    }
  8. ipjohnson commented on Jun 10, 2020

    @ipjohnson
    Owner

    The normal Singleton lifestyle "roots" everything so that no context is carried over as well as no dependencies can be carried. This is to insure that an instance is created the same no matter which parent is constructed first (otherwise you can end up with race conditions where it constructs differently between runs).

    I can make some changes to the deferred singleton lifestyle to make this possible but I can't do it today.

  9. silkfire commented on Jun 10, 2020

    @silkfire
    ContributorAuthor

    Don't feel stressed, I'm okay with waiting awhile for a proper solution. Great that you were able to pinpoint the cause of this :)

  10. silkfire commented on Jul 6, 2020

    @silkfire
    ContributorAuthor

    Any update on this one, Ian? ☝🏻

  11. ipjohnson commented on Jul 7, 2020

    @ipjohnson
    Owner

    Sorry I've been pretty busy as of late. I have some time this weekend to address a couple Grace items and I'll do a release with this in.

  12. ipjohnson commented on Jul 12, 2020

    @ipjohnson
    Owner

    Ok I've implemented a change to make this possible. Normally a singleton is "rooted" this is to prevent a dependency from being constructed differently based on a race condition. This change makes it so which ever path resolves the dependency first dictates how the dependency is constructed.

    Are you able to test it in the nightly?

  13. ipjohnson commented on Jul 23, 2020

    @ipjohnson
    Owner

    I've released this to nuget. Marking as completed.

  14. 3 remaining items

  15. silkfire commented on Jul 27, 2020

    @silkfire
    ContributorAuthor

    @ipjohnson Thanks for pointing me in the right direction. I tried out your code but it made no difference. In the StaticInjectionContext, the TargetInfo.InjectionDependencyType is still of type Root and I'm not able to determine the caller of the dependency resolution.

    Perhaps I'm misunderstanding some concepts here. The dependency to be resolved is a generic, e.g. IDependency<T>:

    IDependency<Type1> resolves as Dependency1
    IDependency<Type2> resolves as Dependency2

    Grace should cache (store) IDependency<Type1> as a singleton with the implementation of Dependency1 and IDependency<Type2> as a singleton with the implementation of Dependency2.

  16. silkfire commented on Jul 28, 2020

    @silkfire
    ContributorAuthor

    I think I've realized that I might've been wrong all along.

    1. The dependency to resolve is an interface, let's call it IDependency.
    2. The implementation is a generic class, call it Dependency<T>.
    3. I assume that this dependency has to be registered with a Transient lifestyle.
    4. Depending on what class calls on the dependency, I want a different Dependency<T> to be resolved.
    5. If Dependency<T> isn't already registered by Grace, create the instance and then store it as a singleton.
    6. If it has been registered previously, return the stored singleton.

    So the Transient IDependency would act as a proxy to the singleton implementation of type Dependency<T>.

  17. ipjohnson commented on Jul 28, 2020

    @ipjohnson
    Owner

    I think I understand what you're talking about. I don't really have a life style that's going to do that but I think it can be achieved with a little bit of code.

    I'll try and find some time today or tomorrow morning to write up an example of what it would look like.

  18. silkfire commented on Jul 28, 2020

    @silkfire
    ContributorAuthor

    Thank you. Apologies for my confusing train of thought 😅

  19. ipjohnson commented on Jul 30, 2020

    @ipjohnson
    Owner

    Ok I added a test where you inject a transient with a non generic interface, where the implementation is a generic that is closed by the injecting type and singleton. Let me know if this is close to what you were thinking.

  20. silkfire commented on Jul 31, 2020

    @silkfire
    ContributorAuthor

    The test looks good in my eyes! Will I be able to read which class was calling on the dependency as the Lifestyle is Transient?
    Also, does it have to specifically be a generic implementation? IMHO IDependency could link to any class based on some custom condition or dependent on which class is trying to resolve the dependency.

  21. ipjohnson commented on Jul 31, 2020

    @ipjohnson
    Owner

    Correct, it doesn't need to be generic nor do you need the concurrent dict. It was just an interesting proof of concept where you close the generic with the parent type.

  22. silkfire commented on Aug 3, 2020

    @silkfire
    ContributorAuthor

    Is this planned for an upcoming release?

  23. ipjohnson commented on Aug 4, 2020

    @ipjohnson
    Owner

    The latest code line is released as a beta on nuget. I'll probably look to do a non beta release in the next week or two.

  24. silkfire commented on Dec 29, 2020

    @silkfire
    ContributorAuthor

    Hey @ipjohnson, I've had some time to take a closer look at this during the holidays but am yet to get it to work. The result I'm getting is the one I mention in #264 (comment) and I've tried using the custom Deferred lifestyle but it doesn't seem to have any effect.

    Can it be of importance that I'm requesting this dependency through a Controller method via the [FromServices] attribute?

  25. ipjohnson commented on Dec 30, 2020

    @ipjohnson
    Owner

    Hi @silkfire

    you’re correct the [FromServices] attribute is handled through the MVC framework and is a new request to the container.

  26. azuraji commented on Dec 30, 2020

    @azuraji

    Hmmm, so that's why it hasn't been working all along. Is there a way this can be solved?

  27. ipjohnson commented on Dec 30, 2020

    @ipjohnson
    Owner

    Not without completely changing the way the [FromService] attribute works.

  28. silkfire commented on Dec 30, 2020

    @silkfire
    ContributorAuthor

    @ipjohnson Shame, I find it quite useful. Would it be possible to hack up a custom one, and let's call it [FromGrace]? 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions