Registering using Attributes

192 views
Skip to first unread message

Robert Wagner

unread,
Dec 5, 2011, 6:26:47 AM12/5/11
to aut...@googlegroups.com
Not sure if it's been floated before, but what about putting attributes on the concrete types so that Autofac can figure out how a component should be registered with no further information. Usually the component is the one that knows what the lifetime scope should be, the other attributes is debatable however.


The registration would look like this:
    var builder = new ContainerBuilder();
    builder.RegisterByAttributes(typeof(MyClass).Assembly);
    _container = builder.Build();

And a sample of the components:

    public interface ISingleInstanceClass {}
 
    [SingleInstance]
    public class SingleInstanceClass : ISingleInstanceClass {}
 
    public interface IInstancePerDependencyClass {}
 
    [InstancePerDependency]
    public class InstancePerDependencyClass : IInstancePerDependencyClass {}
 
 
    public interface IConcreteTypeRegistrationClass {}
 
    [SingleInstance(AsImplementedInterface = false)]
    public class ConcreteTypeRegistrationClass : IConcreteTypeRegistrationClass {}
 
 
    [SingleInstance(AsImplementedInterface = false)]
    [SingleInstance(Name = "Test", AsImplementedInterface = false)]
    public class MultiRegistrationClass {}

Tomek Pluskiewicz

unread,
Dec 5, 2011, 12:28:42 PM12/5/11
to aut...@googlegroups.com
Almost like MEF. I support this idea. 

I would suggest looking at the attributes that already exist in System.ComponentModel.Composition namespace. I don't think they are sealed so extending could also be possible.

Travis Illig

unread,
Dec 5, 2011, 12:43:16 PM12/5/11
to Autofac
The idea is interesting, surely, and the implementation appears simple
enough.

From a use case perspective... it's sort of a personal preference
issue. The team I work with prefers not to mix the DI technology into
the business code, so we specifically look for ways to not mark things
with attributes.

I'm sure if you wanted to add a contrib project with this stuff, you
could do that. You'd probably want a few more extension methods, like
the ability to register individual types by attribute rather than
whole assemblies, and you'd probably want to return the registration
info from the extension method (the way RegisterAssemblyTypes does) so
you could chain things together like
builder.RegisterTypesByAttribute(assembly).InNamespace("Just.This.Namespace");

-T

Nicholas Blumhardt

unread,
Dec 6, 2011, 12:54:07 AM12/6/11
to aut...@googlegroups.com
Hi Rob!

Steve Hebert had a shot at this some time ago - the implementation is in contrib: http://code.google.com/p/autofac/source/browse/#hg%2Fcontrib%2FSource%2FAutofacContrib.Attributed

My thoughts on this have shifted, as have everybody's over the years. I've ended up liking attributes quite a bit for this kind of markup, but there's a lot of work involved in making them feel first-class, e.g. sensible behaviour and exceptions when attributes and rules interact/conflict, and so-on. Probably too much churn to do in the core at this point.

Most of the time this comes up, as you observed it is sharing that needs to be described. I have thought a few times about adding specific support to the scanning API to make it simpler to implement your own custom attributes by reading them in a scanning rule. Never made it to an implementation. Perhaps a helper based on a scoping enum would do it:

// Calculate sharing based on scanned type,
// simple options:
builder.RegisterAssemblyTypes(a)
    .Share(t => Instance.Single);

And thus you could create a .ReadMyAttribute() extension to wrap up sharing configuration based on 't'.

Getting this one to cover all kinds of scoping we support would probably call for another overload surfacing the underlying RegistrationBuilder:

// Calculate sharing based on scanned type,
// all sharing methods supported:
builder.RegisterAssemblyTypes(a)
    .Share((t, b) => b.SingleInstance());

The 'b' parameter would allow for things like .InstancePerOwned<IFoo>() (nice job Alex on this little recent addition.)

Does this line up with what you need in the app you're working on?


--
You received this message because you are subscribed to the Google Groups "Autofac" group.
To post to this group, send email to aut...@googlegroups.com.
To unsubscribe from this group, send email to autofac+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/autofac?hl=en.


Travis Illig

unread,
Dec 6, 2011, 12:29:54 PM12/6/11
to Autofac
Actually, a nice standardized attribute design might be something like
(without running through a compiler)

public abstract AutofacRegistrationAttribute : Attribute
{
public abstract void
Register<TImplementor>(IRegistrationBuilder<TImplementor,
ConcreteReflectionActivatorData, SingleRegistrationStyle>
registration);
}

Custom attributes could derive from AutofacAttribute

public InstancePerDependencyAttribute : AutofacRegistrationAttribute
{
public abstract void
Register<TImplementor>(IRegistrationBuilder<TImplementor,
ConcreteReflectionActivatorData, SingleRegistrationStyle>
registration)
{
registration.InstancePerDependency();
}
}

The assembly scanning registration callback could find any attributes
derived from AutofacAttribute, do the RegisterType() call on them, and
just pass to the Register method on each attribute found.

You could do pretty much anything at that point - do additional custom
scanning for metadata, set lifetime, or whatever. Probably wouldn't be
too much churn in the core, but I admit I've not thought it totally
through. :)

On Dec 5, 9:54 pm, Nicholas Blumhardt <nicholas.blumha...@gmail.com>
wrote:


> Hi Rob!
>
> Steve Hebert had a shot at this some time ago - the implementation is in

> contrib:http://code.google.com/p/autofac/source/browse/#hg%2Fcontrib%2FSource...

Matt Jackson

unread,
Dec 6, 2011, 2:56:00 PM12/6/11
to Autofac
Wouldn't this add heavy coupling of to Autofac throughout your entire
codebase? I thought the goal of an IOC container was to make the
specifics of constructing an object graph orthogonal to your codebase?

Robert Wagner

unread,
Dec 7, 2011, 6:04:05 AM12/7/11
to aut...@googlegroups.com
Matt,

Yes it would tie the implementations to Autofac, but whether that is a bad thing varies person to person. Personally the reason I use IoC is because it focuses you onto the SRP and for (dare I say it) testability. I can see your point if you believe in pure POCO, but we are taking a bit of a hybrid approach.

My main reason for doing this is that I've found that often the registrations become unmanageable (too big or too many modules) and also sometimes it's hard to figure out how something got registered and with what parameters.

Rob

Robert Wagner

unread,
Dec 7, 2011, 6:10:54 AM12/7/11
to aut...@googlegroups.com
Travis,

Thanks for that. The thought crossed my mind to just mark up the class with attributes per registration step, but I initially rejected the idea because then you couldn't register a class more than once. However thinking about the 80% use case*, multi-registrations wouldn't occur and I've thought about a way of doing it now (Cludgy though).

* 80% use-case would be Register each type once, either Single or PerLifetime scope and either Concrete or ImplementedInterfaces. Anything the attributes didn't handle would be done the other way(s). Just thinking out loud here.

I'll bang away at it.

Thanks

Rob

Robert Wagner

unread,
Dec 7, 2011, 6:16:06 AM12/7/11
to aut...@googlegroups.com
Hey Nick,

Thanks for the ideas and link. 

This idea was born out of a debugging session on a previous project trying to figure out how something got registered twice with difference lifetimes. I've got just the right project to try the ideas out on however.

Rob
Reply all
Reply to author
Forward
0 new messages