Event After Registration

May 5 at 5:00 PM
Is there a way to register an extension to execute an event after a registration?
I saw that there is an event in the ExtensionContext class called Registering.
May 5 at 6:57 PM
Can you explain why you need that?
May 5 at 7:09 PM
I have a Manager class that loads the containers from the config, and then the manager gets all the registered RegistrationConvention and execute them to register the return of the registration convention.

This manager works fine, but to make it work in any device, I should remove the reference to the registrationconvention, and to make this I need to execute all of the registration conventions that are registered in the unity, the best event to do this is right after the registration convention class is registered in the unity container ( either by code or by unity.config)


Do you prefer if I put an example?
Editor
May 6 at 5:30 AM
I think that Context.Registering of a ContainerExtension should be able to do what you want.

Here's a simple example that performs a resolve of the registered concrete type:
    public class RegistrationExtension : UnityContainerExtension
    {
        protected override void Initialize()
        {
            Context.Registering += AddRegistration;
        }

        private void AddRegistration(object sender, RegisterEventArgs e)
        {
            if (e.TypeTo == typeof(MyClass))
            {
                var myClass = Container.Resolve(e.TypeFrom, e.Name);
            }
        }
    }

Note that when Registering is called injection members will not have been applied yet so don't depend on that situation.

One alternative approach is to bootstrap Unity and register your convention classes and then after registration resolve all convention classes (using common interface or register the conventions as array and use ResolveAll for example) and then invoke the appropriate method to execute the convention.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
May 6 at 3:32 PM
My actual code is your alternative approach, I'm changing it so I can use the same loader in all platforms.

I'll try this extension and then I'll post here the result.

Thanks
May 23 at 9:14 PM
It worked all right, but there's small issue:

if I use this code Container.Resolve(e.TypeFrom, e.Name) inside the Registering event, somehow the container doesn't choose the correct constructor

in the unity.config I have this registration with an empty constructor tag, after the registering event the container uses the empty constructor, but inside the event, the container gets the constructor with more parameters.


Is this the correct behavior?
Editor
May 24 at 3:42 AM
Edited May 24 at 3:42 AM
Yes, that is the behavior I would expect. What you are seeing is what I previously wrote:
Note that when Registering is called injection members will not have been applied yet so don't depend on that situation.
As I understand it, you want to register classes via configuration and then after that run a "convention" that will map the registered classes without altering the existing registration. You can do that by just iterating through the registrations (not usually recommended but in this case should be OK as long as it's done once at startup):
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();

foreach (var registration in container.Registrations)
{
    // Ignore Unity or perhaps some opt-in logic
    if (!registration.RegisteredType.Namespace.StartsWith("Microsoft.Practices.Unity"))
    {
        // Map Class to IClass
        string typeName = "I" + registration.RegisteredType.Name;
        var type = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a => a.GetTypes())
            .FirstOrDefault(t => t.Name == typeName); 

        container.RegisterType(type, registration.RegisteredType);
    }
}

Or another approach would be to use a container extension that registers a type mapping when a class is registered.
public class RegistrationExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Registering += AddRegistration;
    }

    private void AddRegistration(object sender, RegisterEventArgs e)
    {
        // Any check to know that you want to map the type
        if (e.TypeFrom == null)
        {
            // Any mapping convention you want to create
            string typeName = "I" + e.TypeTo.Name;
            var type = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(s => s.GetTypes())
                .FirstOrDefault(p => p.Name == typeName);

            if (type != null)
            {
                Context.Policies.Set<IBuildKeyMappingPolicy>(
                    new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo, e.Name)),
                    new NamedTypeBuildKey(type, e.Name));
            }
        }
    }
}

IUnityContainer container = new UnityContainer();
container.AddNewExtension<RegistrationExtension>();
container.LoadConfiguration();

The last way is a bit cleaner.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to