Dependency Attributes only on Field and Property

Topics: CAB & Smart Client Software Factory
Jul 11, 2005 at 5:55 AM
originally posted by: eilert

The ComponentDependency- and ServiceDependencyAttribute are only allowed on Fields and Properties and only ones.

The above forces you to have a reference to the dependent component or service in your class.

However there are scenarios were classes only need to signal that certain components and or services be present.

eg. You might have a SecurityMonitor component, which allows methods to run only if certain conditions are met. That same could be done with classes.

Also classes may need more then one component or service, which is also impossible, since only one dependency attribute is allowed.
The dependency injection mechanism relies on the examination of the type the field or property has, to inject the correct component or service. This should also be changed, so that the type of component or service can be specified.

CAB is a very extensible and composible framework. This allows one to to design simpler classes, thus achieving good sepperation of concerns. However these classes almost certainly will rely on other components and services to be present.
Aug 15, 2005 at 10:34 AM
originally posted by: BradWilsonMSFT

Can you clarify with example code what you mean and what the requirement is that you're trying to fulfill?
Oct 12, 2005 at 12:54 AM
originally posted by: blc_do

Is there a reason wits this behavior was changed For the Dependency and CreateNew Attributes?
Oct 12, 2005 at 3:14 AM
originally posted by: BradWilsonMSFT

The dependency injection system changed a great deal in CTP2. Which behavior are you talking about?
Oct 12, 2005 at 3:34 AM
originally posted by: blc_do

Both Attributes are now marked with

AttributeTargets.Property | AttributeTargets.Parameter

instead of

AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Field

This makes life a pain for VB Programmers, lots of boilerplate to generate. (And yes I am at present not only painfully going through the HOL and translating from the June to the October CTP but also from C# to VB. I'm also completely new to the CAB. Fun Project.)

I don't know if you want to be able to do this, but shouldn't I also be able to handle private fields if I simply give them this attribute. You'd have to touch the IoC code slightly to handle this in the reflection but it might be worth the trade off. (I haven't looked at the security rammifications of this change though.)
Oct 12, 2005 at 4:07 AM
originally posted by: BradWilsonMSFT

A big change from June to October is that we no longer inject into privates, for a variety of reasons (we're working on a post describing the new injection system, which should cover some of this).

Now, faced with supporting public injection only, we decided that it wasn't appropriate to support field injection, because that would encourage public fields which break OO encapsulation.

However, we do support more injection styles than just properties. We can now do constructor and public method injection as well (which is why those attributes are decorated with AttributeTargets.Parameter).
Oct 13, 2005 at 3:56 AM
originally posted by: EdJez

That said, please speak up if you think the injection on public fields was helpful, even considering the tradeoff with stylistic OO implications.
Oct 13, 2005 at 4:48 AM
originally posted by: blc_do

If you work from a code generation point of view, it won't make much difference. If you're typing in VB, you have a lot more to do.

This really won't break anything. I do actually prefer properties but your HOL seemed to indicate fields would be OK. My problem is not to ALLOW the injection onto fields. Frameworks really shouldn't dictate style, just function and .NET allows us to create and use Public fields. Change .NET and I would say you're ok.

Having said that, I'd probably rather be able to inject into private properties than public fields but that would be a security nightmare. I should think that the properties I'm 'exposing' (i.e. marking with the attribute) to the CAB shouldn't necessarily be seen by the rest of my module. They might just interest my local class and not the rest of the module. (I can always hide them in the browser though, always a first line of defense :.)
Oct 13, 2005 at 5:29 AM
originally posted by: BradWilsonMSFT

We also support constructor injection. In the October release, ServiceDependency, ComponentDependency and CreateNew work on Constructor parameters. For the final release, we want to also get State, TraceSource, and Configuration work as well.

This allows you to write a constructor and mark it for dependency injection, without forcing public setters. An example of how this works:

public class Foo
{
private IMyService svc;

InjectionConstructor
public Foo(ServiceDependency IMyService svc)
{
this.svc = svc;
}
}

Now nothing is exposed to the outside world. Normal users know that you expect a service, and when creating you, will need to provide one. When you're dependency injected, CAB will resolve this for you.

The obvious caveat is that CAB needs to be the guy calling your constructor. So this works for the AddNew family of methods (Items.AddNew, Services.AddNew, etc.), but not for the Add family (which takes an existing object which somebody else already constructed).
Oct 13, 2005 at 6:07 PM
originally posted by: blc_do

I think I understand all that. But why do I need to to expose anything other then the attribute?

I look at marking things with attributes like creating an interface without explicitly naming it. Let's take a look at the following (VB, yes I am a Heritic) code snippit:

Public Interface IFoo
Property Bar() As String
End Interface

Public Class Foo
Implements IFoo

Private mBar As String
Private Property Bar() As String Implements IFoo.Bar
Get
Return mBar
End Get
Set(ByVal value As String)
mBar = value
End Set
End Property
End Class

Module Module1

Sub Main()
Dim f As IFoo = New Foo
f.Bar = "Test"
Console.WriteLine(f.Bar)

Dim f2 As Foo = New Foo
'f2.Bar = Test 'Doesn't work because the property isn't there.
'Console.WriteLine(f2.Bar) 'Doesn't work because the property isn't there.

Console.ReadLine()
End Sub

End Module

My Foo Class doesn't expose ANY properties. Only those users of the IFoo interface that know that Foo implements IFoo will be able to use and see the Bar property.

Now, let's look at your Attribute/Property, Attribute/Method pairs as an Interface implicitly and not explicitly named. The rest of my module shouldn't worry about the plumbing I'm setting up to get to the information from the CAB. Anyone using my module shouldn't need to see these variables just because I needed them to use the CAB. I should be able to hide it from the rest of the module.

You said it yourself
>The obvious caveat is that CAB needs to be the guy calling your constructor.

I'd rather have

public class Foo
{
private IMyService svc;

InjectionConstructor
private Foo(ServiceDependency IMyService svc)
{
this.svc = svc;
}
}

And then only the CAB will usually call the constructor. I don't have to worry about someone trying to instance this class without knowing what they are doing.

If you use direct injection into Private members (either fields or properties) or allow calling Private methods you are doing nothing other than what the normal .NET Interface definition does. You are just implicitly defining the Interface using either an Attribute/Type or Attribute/Method pair and using reflection to find it at runtime as opposed to setting up an explicit name during design.

I doubt I can convince you to change this but I seriously don't understand why you make your 'implicit interfaces' work differently from a normal Interface definition. The only real reason I can think of might be security limitations (keeping someone evil from adding evil things to my app) but I really don't win anything. As it stands now anyone can and could access those properties. I make them private, I raise the bar one knowledge level higher.

Thanks for looking at this BTW.
Oct 14, 2005 at 12:41 AM
originally posted by: eilert

I think one also has to look at other technologies like Indigo (WCF), which are being developed, which also have dependency injections and align with them for possible future extensions.
Indigo does allow injection into private fields or properties (I do'nt know if this changed in the latest CTP's).
Maybe one could talk to them about their reasoning and security implications.
Oct 14, 2005 at 4:28 AM
originally posted by: BradWilsonMSFT

There are many technical differences between CAB and Indigo. As one example of why we can't do this: our code needs to be able to run in the sandbox, where private reflection isn't allowed.
Oct 14, 2005 at 5:04 AM
originally posted by: blc_do

I was afraid of that. Thanks anyway.
Oct 14, 2005 at 5:58 PM
originally posted by: PProvost

I just wrote a blog post about this very topic:

http://www.peterprovost.org/archive/2005/10/13/8606.aspx