Attribute support in StructureMap 3.0 -- Proposed

231 views
Skip to first unread message

Jeremy Miller

unread,
Feb 8, 2013, 10:33:17 AM2/8/13
to structure...@googlegroups.com
As I alluded to in earlier blog posts and messages, I would like to thin down or flat out eliminate the attribute support in StructureMap 3.0.  The old [PluginFamily]/[Pluggable] scheme was designed in late 2003 in a very database centric kind of way.  I personally haven't used these attributes in years and frankly never would again.  Moreover, they're a supportability nightmare because of the way it takes attributes on both the interface and concrete type with some magic string goo in the mix too meaning that you can never understand exactly how StructureMap is going to behave with the decorated types unless you're looking at both [PluginFamily] and [Pluggable] attributes at the exact same time.  That folks is how you make an awesomely bad early .Net framework.

My proposal, and speak quickly here because I want this to go fast:

[PluginFamily] is dead, dead, dead.  The only pushback I've heard on this is being able to set scope via attributes instead of explicitly in a Registry.  Personally, I'm not terribly concerned about that, but one user was, so more on that below.

[Pluggable] lives, but it changes.
  * "ConcreteKey" --> "Name" because that's all it is is the name of an Instance.  Name will be optional
  * ExportTo = Type[] -- optional Array of types that this will "plug into".  If this is blank, StructureMap will look to see what interfaces it implements and maybe an abstract class too (but only one parent up) and plug this type into each of those.
  * Scope = Lifecycle.Whatever -- so you can control the scoping here.
  * ScopeType : Type -- so you can use your own special scoping -- SM3 will allow you to specify the scope instance by instance.  Should have done this years ago, but at least it's happening now.

[Singleton] -- shortcut to do [Pluggable(Scope = Lifecycle.Singleton)]


And the best part, with the new StructureMap 3.0 model that should be much cleaner, it should be possible to bring back the old attribute behavior as an extension nuget that works strictly by type scanning.

Thanks,

Jeremy




Jeremy Miller

unread,
Feb 8, 2013, 11:28:04 AM2/8/13
to structure...@googlegroups.com
The more that I think about this, I think we shove the old attributes into a new StructureMap.LegacyAttributeSupport package.

In the core, we add the new attributes for:

[Instance] and [Singleton] that do the stuff above.

Frank L. Quednau

unread,
Feb 8, 2013, 11:33:25 AM2/8/13
to structure...@googlegroups.com
I would be even harsher and not implement those Singleton attribs etc. as well. It is so easy to write a convention that does the same based on your own attribute. I will gladly write a blog post that show an example you can point to when the time comes :)

Steven Smith

unread,
Feb 8, 2013, 12:00:25 PM2/8/13
to structure...@googlegroups.com
I too never use any of the attributes, and wouldn't use the proposed
new ones, either.
> --
> You received this message because you are subscribed to the Google Groups
> "structuremap-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to structuremap-us...@googlegroups.com.
> To post to this group, send email to structure...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/structuremap-users/-/0k2fkOd3PPsJ.
>
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Steve Smith
http://Ardalis.com/
http://twitter.com/ardalis

Jimmy Bogard

unread,
Feb 8, 2013, 2:28:41 PM2/8/13
to structure...@googlegroups.com
Can we have attributes that integrate with the XML config?

[Pluggable("<PluginFamily type='IFoo' />")]


--
You received this message because you are subscribed to the Google Groups "structuremap-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to structuremap-us...@googlegroups.com.
To post to this group, send email to structure...@googlegroups.com.

Jos Krause

unread,
Feb 12, 2013, 8:27:55 AM2/12/13
to structure...@googlegroups.com
Hey Frank,

That's exactly what we have done;this is what I have in my current project (perhaps could be cleaner, code is old):

    public class SingletonConvention : IRegistrationConvention
    {
        public void Process(Type type, Registry registry)
        {
            if (!type.IsConcrete() || !type.CanBeCreated())
                return;

            if (!type.HasAttribute<SingletonAttribute>()) // Simple extension method to reflect the attributes
                return;

            var interfaceName = GetDefaultInterfaceName(type);
            var interfaceType = type.GetInterface(interfaceName);

            if (interfaceType == null)
                return;

            registry.For(interfaceType).Singleton().Use(type);
        }

        private string GetDefaultInterfaceName(Type type)
        {
            return string.Format("I{0}", type.Name);
        }
    }


As for the attribute itself (Warning: scary code ahead!):

    public class SingletonAttribute : Attribute
    {
    }

And the extension methods:

        /// <summary>
        /// Indicates whether the given type has any attribute of the specified attribute type.
        /// </summary>
        /// <typeparam name="TAttribute">The type of the attribute.</typeparam>
        /// <param name="value">The object instance to check.</param>
        /// <returns>A boolean indicating whether <paramref name="value"/> contains any attribute of type <typeparamref name="TAttribute"/></returns>
        public static bool HasAttribute<TAttribute>(this Type value) where TAttribute : Attribute
        {
            return value.GetAttributes<TAttribute>().Any();
        }

        /// <summary>
        /// Determines whether an instance implements the specified interface.
        /// </summary>
        /// <typeparam name="TInterface">The interface that has to be implemented by <paramref name="type"/></typeparam>
        /// <param name="type">The type that has to implement <typeparamref name="TInterface"/></param>
        /// <returns>A boolean indicating whether <paramref name="type"/> implements <typeparamref name="TInterface"/>.</returns>
        public static bool Implements<TInterface>(this Type type)
        {
            return typeof(TInterface).IsAssignableFrom(type);
        }

        /// <summary>
        /// Returns a sequence of attributes for the given type.
        /// </summary>
        /// <typeparam name="TAttribute">The type of the attribute.</typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        private static IEnumerable<TAttribute> GetAttributes<TAttribute>(this Type value) where TAttribute : Attribute
        {
            var attributes = value.GetCustomAttributes(true);

            return attributes.Length == 0 ? Enumerable.Empty<TAttribute>() : attributes.Cast<Attribute>().OfType<TAttribute>();
        }


--
You received this message because you are subscribed to the Google Groups "structuremap-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to structuremap-us...@googlegroups.com.
To post to this group, send email to structure...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages