Unity Static Property Injection
Asked Answered
R

2

7

I have two classes, one which sets up the container by registering types and one which contains a static property which I want to inject into. My issue is the property is never set by injection so when I call a method on it, the property is always null.

public class ClassOne
{
    public void Method()
    {
        Container.RegisterType<IClass, ClassImplOne>("ImplOne");
        Container.RegisterType<IClass, ClassImplTwo>("ImplTwo");
    }
}

public static class ClassTwo
{
    [Dependency]
    public static IClass SomeProperty { get; set; }

    public static void SomeOtherMethod()
    {
        SomeProperty.AnotherMethod();
    }
}

If I remove the Dependency attribute and in ClassOne do a simple

ClassTwo.SomeProperty = Container.Resolve<IClass>("ImplOne");

it works fine, but I want to know if it is possible to do this without explicitly assigning a value to the property (i.e. can the container inject through attributes)?

Edit:

Thanks. I have removed the static declaration from ClassTwo and in ClassOne added RegisterType and Resolve for ClassTwo and also added InjectionProperty:

Container.RegisterType<IClass, ClassImplOne>("ImplOne", new InjectionProperty("SomeProperty"));

but it still does not work :S

Reversal answered 28/2, 2013 at 11:40 Comment(1)
Edited my answer to be more specific.Plonk
P
6

Unity inject dependencies when the class is resolved through Unity. A static class can not be created, so Unity can not inject dependencies.

Instead of having a Static class, use Unity to resolve a pseudo-singleton class (ContainerControlledLifetimeManager) of ClassTwo. This way Unity injects IClass to ClassTwo when ClassTwo is created (resolved throug Unity container) and, as is configured as singleton, you always have the same instace of ClassTwo in the whole lifecicle of your application.

You must resolve ClassTwo through Unity.

Container.RegisterType<IClass, ClassImplOne>("ImplOne");
Container.RegisterType<IClass, ClassImplTwo>("ImplTwo");
Container.RegisterType<InterfaceImplemetedByClassTwo, ClassTwo>();

//Simple example. Don't forget to use ContainerControlledLifetimeManager for ClassTwo to simulate sigleton.

And when you need ClassTwo:

Container.Resolve<InterfaceImplemetedByClassTwo>

Having the config in ClassTwo:

public class ClassTwo : InterfaceImplemetedByClassTwo
{
    [Dependency("ImplOne")] //inject ClassImplOne
    public IClass SomeProperty { get; set; }

BUT this is not a great solution, I think your problem is with the phylosophy of DI. You need to cascade dependencies from the top layer classes of your app. Resolve the top layer classes in a explicit way. (Container.Resolve) and dependecies injection cascade down thanks to the magic of Unity. When 2 classes (top layer or not) need to use the same instance of ClassTwo Unity do the dirty work if you configured ClassTwo with ContainerControlledLifetimeManager.

In other words, you don't need static class, you inject the same instance of a class in other classes than need it.

Plonk answered 28/2, 2013 at 12:11 Comment(3)
Thanks, I've replicated what you said and it's still not working. ClassTwo being static was only because all the constituents are static as they are bound to Excel and the Office Ribbon through ExcelDNA and XML. I've removed the static keyword from the class, registered ClassTwo and resolved it after registering ClassImplOne but the property is still null.Reversal
Unity will only inject instance properties - you need to take the static off the property declaration as well.Tuff
Sorry for the mistake in copy/paste your code, Chris is right. Remove all static declarations in your classes. I will edit my answer as the code is contradictory with the text.Plonk
K
7

Edited after considering comments:

There are a variety of reasons why at times you still want or need to use static classes instead of cascading everything through Unity.

If the static class has a dependency on another class that you would want to be configurable/exchangeable via your Unity configuration I prefer using a factory pattern as described at How to resolve dependency in static class with Unity? or simply assigning a function to resolve the dependency when needed, rather than referencing the Container from within the static class. One advantage being that all your Unity configuration can be in the same place.

In your case it could look like this:

public static class ClassTwo
{
    private static IClass _someProperty;

    public static Func<IClass> ResolveProperty { private get; set; }

    private static IClass SomeProperty
    {
        get { return _someProperty ?? (_someProperty = ResolveProperty()); }
    }

    public static void SomeOtherMethod()
    {
        SomeProperty.AnotherMethod();
    }

}

And in your Unity configuration add this:

ClassTwo.ResolveProperty = () => container.Resolve<IClass>();
Karenkarena answered 18/3, 2016 at 10:39 Comment(0)
P
6

Unity inject dependencies when the class is resolved through Unity. A static class can not be created, so Unity can not inject dependencies.

Instead of having a Static class, use Unity to resolve a pseudo-singleton class (ContainerControlledLifetimeManager) of ClassTwo. This way Unity injects IClass to ClassTwo when ClassTwo is created (resolved throug Unity container) and, as is configured as singleton, you always have the same instace of ClassTwo in the whole lifecicle of your application.

You must resolve ClassTwo through Unity.

Container.RegisterType<IClass, ClassImplOne>("ImplOne");
Container.RegisterType<IClass, ClassImplTwo>("ImplTwo");
Container.RegisterType<InterfaceImplemetedByClassTwo, ClassTwo>();

//Simple example. Don't forget to use ContainerControlledLifetimeManager for ClassTwo to simulate sigleton.

And when you need ClassTwo:

Container.Resolve<InterfaceImplemetedByClassTwo>

Having the config in ClassTwo:

public class ClassTwo : InterfaceImplemetedByClassTwo
{
    [Dependency("ImplOne")] //inject ClassImplOne
    public IClass SomeProperty { get; set; }

BUT this is not a great solution, I think your problem is with the phylosophy of DI. You need to cascade dependencies from the top layer classes of your app. Resolve the top layer classes in a explicit way. (Container.Resolve) and dependecies injection cascade down thanks to the magic of Unity. When 2 classes (top layer or not) need to use the same instance of ClassTwo Unity do the dirty work if you configured ClassTwo with ContainerControlledLifetimeManager.

In other words, you don't need static class, you inject the same instance of a class in other classes than need it.

Plonk answered 28/2, 2013 at 12:11 Comment(3)
Thanks, I've replicated what you said and it's still not working. ClassTwo being static was only because all the constituents are static as they are bound to Excel and the Office Ribbon through ExcelDNA and XML. I've removed the static keyword from the class, registered ClassTwo and resolved it after registering ClassImplOne but the property is still null.Reversal
Unity will only inject instance properties - you need to take the static off the property declaration as well.Tuff
Sorry for the mistake in copy/paste your code, Chris is right. Remove all static declarations in your classes. I will edit my answer as the code is contradictory with the text.Plonk

© 2022 - 2024 — McMap. All rights reserved.