Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity framework DependencyAttribute only works for public properties?

I was trying to clean up some accessability stuff in my code, and inadvertently broke Unity dependency injection. After a while I realized that I marked some public properties that I didn't really want exposed outside my DLLs to internal. Then I started getting exceptions.

So it seems that using the [Dependency] attribute in Unity only works for public properties. I suppose that makes sense since the internal and private props wouldnt be visible to the Unity assembly, but feels really dirty to have a bunch of public properties that you never want anyone to set or be able to set, other than Unity.

Is there a way to let unity set internal or private properties too?

Here is the unit test I'd like to see pass. Currently only the public prop test passes:

    [TestFixture]
public class UnityFixture
{
    [Test]
    public void UnityCanSetPublicDependency()
    {
        UnityContainer container = new UnityContainer();
        container.RegisterType<HasPublicDep, HasPublicDep>();
        container.RegisterType<TheDep, TheDep>();

        var i = container.Resolve<HasPublicDep>();
        Assert.IsNotNull(i);
        Assert.IsNotNull(i.dep);
    }

    [Test]
    public void UnityCanSetInternalDependency()
    {
        UnityContainer container = new UnityContainer();
        container.RegisterType<HasInternalDep, HasInternalDep>();
        container.RegisterType<TheDep, TheDep>();

        var i = container.Resolve<HasInternalDep>();
        Assert.IsNotNull(i);
        Assert.IsNotNull(i.dep);
    }

    [Test]
    public void UnityCanSetPrivateDependency()
    {
        UnityContainer container = new UnityContainer();
        container.RegisterType<HasPrivateDep, HasPrivateDep>();
        container.RegisterType<TheDep, TheDep>();

        var i = container.Resolve<HasPrivateDep>();
        Assert.IsNotNull(i);
        Assert.IsNotNull(i.depExposed);
    }
}

public class HasPublicDep
{
    [Dependency]
    public TheDep dep { get; set; }
}

public class HasInternalDep
{
    [Dependency]
    internal TheDep dep { get; set; }
}

public class HasPrivateDep
{
    [Dependency]
    private TheDep dep { get; set; }

    public TheDep depExposed
    {
        get { return this.dep; }
    }
}

public class TheDep
{
}

Updated:

I noticed the call stack to set the property passed from:

UnityCanSetPublicDependency()
--> Microsoft.Practices.Unity.dll
--> Microsoft.Practices.ObjectBuilder2.dll
--> HasPublicDep.TheDep.set()

So in an attempt to at least make the internal version work, I added these to my assembly's properties:

[assembly: InternalsVisibleTo("Microsoft.Practices.Unity")]
[assembly: InternalsVisibleTo("Microsoft.Practices.Unity.Configuration")]
[assembly: InternalsVisibleTo("Microsoft.Practices.ObjectBuilder2")]

However, no change. Unity/ObjectBuilder still won't set the internal property

like image 704
CodingWithSpike Avatar asked Jan 23 '09 16:01

CodingWithSpike


3 Answers

Another solution is to use [InjectionMethod] on a method where you pass the dependency into the class.

public class MyClass {
private ILogger logger;

[InjectionMethod]
public void Init([Dependency] ILogger logger)
{
    this.logger = logger;

...etc


and calling it:

container.BuildUp<MyClass>(instanceOfMyClass);

which will call Init with the dependency from unity.

didn´t quite solve the problem, I know...but

:-) J

like image 80
Johan Leino Avatar answered Nov 06 '22 23:11

Johan Leino


If the property is get-only, it makes more sense to use contructor injection rather than property injection.

If Unity did use reflection to set private or internal members, it would be subjected to code access security constraints. Specifically, it wouldn't work in a low-trust environment.

like image 31
Kent Boogaart Avatar answered Nov 06 '22 22:11

Kent Boogaart


The question itself seems to be a misunderstanding.

Regarding the core statement:

a bunch of public properties that you never want anyone to set or be able to set, other than Unity.

You would want to set them in unit tests, or how else would you pass dependency mocks? Even if you don't have unit tests, it's a strange idea to have dependencies that nothing (except some magic of Unity) can set. Do you want your code to depend so much on support tool?

Also, having public properties is not an issue at all, because your code MUST depend on interfaces, not on implementations (one of SOLID principles). If you don't follow this principle - there is no reason for you to use Unity. Surely you wouldn't declare dependencies in the interface, so the consuming class doesn't know about them.

You've already been told that it's better to use constructor injection, but property injection also has its beauty. It allows adding new dependencies with less modifications (in particular, you can avoid changing existing unit tests at all, only adding new ones).

like image 5
Kurtevich Avatar answered Nov 06 '22 22:11

Kurtevich