Castle Windsor to Unity - can you auto-configure in Unity the same way you can in CW?
Asked Answered
H

5

6

I don't know if this is too specific a question, if that is possible, but I'm having to port an app that uses Castle Windsor to Unity so that there isn't a reliance on non-microsoft approved libraries. I know I know but what are you going to do.

Anyway I've managed it but I'm not happy with what I've got. In Windsor I had this:

Register(
            AllTypes.Of(typeof(AbstractPresenter<>)).FromAssemblyNamed("Links.Mvp"),
            AllTypes.Of(typeof(IView)).FromAssemblyNamed("Links.WinForms").WithService.FromInterface());

which I've converted to this in unity

RegisterType<IMainView, MainView>();
        RegisterType<IConfigureLinkView, ConfigureLinkView>();
        RegisterType<IConfigureSourceView, ConfigureSourceView>();
        RegisterType<IConfigureSinkView, ConfigureSinkView>();
        RegisterType<MainPresenter, MainPresenter>();
        RegisterType<ConfigureLinkPresenter, ConfigureLinkPresenter>();
        RegisterType<ConfigureSourcePresenter, ConfigureSourcePresenter>();
        RegisterType<ConfigureSinkPresenter, ConfigureSinkPresenter>();

As you can see I'm having to register every single thing rather than be able to use some sort of auto-configuration. So my question is: is there a better way of doing this in unity?

Thanks,

Adam.

Hemoglobin answered 24/12, 2008 at 13:19 Comment(2)
An idea would be to rip out the code used for Register() in CastleWindsor's source, and make an extension method off of the Unity container.Bucko
If you're moving to Unity, please accept my condolences. You're up for a world of pain, especially if you have used Windsor extensively, and non-triviallyBroddy
M
0

Cool. This feature is not in unity yet but if you felt a bit ambitious you could setup your own convention based registration. Found below is a snipped that works for the executing assembly and interfaces. Good luck.

P.S. This feels like a big hack, I would probably continue just registering all types by hand.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;

namespace Forum
{
    class Program
    {
        static void Main(string[] args)
        {
            // get your assemblies and types you can register
            Assembly a = Assembly.GetExecutingAssembly();
            var types = a.GetTypes();            
            var bindTo = from t in types
                         where t.IsAbstract || t.IsInterface
                         select t;

            // apply your conventions to filter our types to be registered
            var interfacePairs = from t in bindTo.Where(x => x.IsInterface)
                                 let match = types.FirstOrDefault(x => x.Name ==     t.Name.Substring(1))
                                 where match != null
                                 select new Pair { To = t, From = match };
            var abstractPairs = new Pair[] {};


            // setup the generic form of the method to register the types
            var thisType = typeof(Program);
            var bindings = BindingFlags.Static | BindingFlags.Public;
            MethodInfo genericMethod = thisType.GetMethod("RegisterType", bindings);            

            // register all your types by executing the 
            // specialized generic form of the method
            foreach (var t in interfacePairs.Concat(abstractPairs))
            {
                Type[] genericArguments = new Type[] { t.To, t.From };
                MethodInfo method = genericMethod.MakeGenericMethod(genericArguments);
                method.Invoke(null, new object [] {});
            }

            Console.ReadKey();
        }

        public static void RegisterType<To, From>()
        {
            Console.WriteLine("Register { To: {0} From: {1} }", typeof(To), typeof(From));
        }

        // Test classes that should be picked up
        interface ITest { }
        class Test : ITest { }

        class Pair
        {
            public Type To { get; set; }
            public Type From { get; set; }
        }        
    }
}
Marven answered 25/12, 2008 at 5:46 Comment(2)
Not so much of a hack, as the source to CastleWindsor does something similar (be it, far more elegantly). A better idea for him would be to rip out the code used for Register(), and make an extension method off of the Unity container/Bucko
Just so I am clear you mean taking it out of Windsor then applying it to Unity? Sure why not! Ya... elegance? Maybe next project ; ).Marven
L
5

Check this out:

        var container = new UnityContainer();

        container
            .ConfigureAutoRegistration()
            .LoadAssemblyFrom("Plugin.dll")
            .IncludeAllLoadedAssemblies()
            .ExcludeSystemAssemblies()
            .ExcludeAssemblies(a => a.GetName().FullName.Contains("Test"))
            .Include(If.Implements<ILogger>, Then.Register().UsingPerCallMode())
            .Include(If.ImplementsITypeName, Then.Register().WithTypeName())
            .Include(If.Implements<ICustomerRepository>, Then.Register().WithName("Sample"))
            .Include(If.Implements<IOrderRepository>,
                     Then.Register().AsSingleInterfaceOfType().UsingPerCallMode())
            .Include(If.DecoratedWith<LoggerAttribute>,
                     Then.Register()
                            .AsInterface<IDisposable>()
                            .WithTypeName()
                            .UsingLifetime<MyLifetimeManager>())
            .Exclude(t => t.Name.Contains("Trace"))
            .ApplyAutoRegistration();
Late answered 8/10, 2009 at 9:55 Comment(2)
shameless self promotion! I love it.Marven
Also very nice source code. If I have to use Unity I will definitely include it ;).Marven
Z
2

Unity 3 now supports registration by convention out of the box.

The following would register and map all your concrete implementations to an interface that follows the convention: IFoo -> Foo

var container = new UnityContainer();
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.MatchingInterface,
    WithName.Default);

By the way, you do not need to register concrete type classes (as is the case with your XXXPresenter classes) if they do not map to a different type... Unity will automatically build it up if a class depends on a concrete type.

There's a lot more you can do with conventions, like filtering which assemblies or types to use, or how the mapping is done, but I'd suggest you look at the examples in MSDN, as they cover several of these:

http://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx#sec23

Zia answered 5/6, 2013 at 20:37 Comment(0)
M
0

Cool. This feature is not in unity yet but if you felt a bit ambitious you could setup your own convention based registration. Found below is a snipped that works for the executing assembly and interfaces. Good luck.

P.S. This feels like a big hack, I would probably continue just registering all types by hand.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;

namespace Forum
{
    class Program
    {
        static void Main(string[] args)
        {
            // get your assemblies and types you can register
            Assembly a = Assembly.GetExecutingAssembly();
            var types = a.GetTypes();            
            var bindTo = from t in types
                         where t.IsAbstract || t.IsInterface
                         select t;

            // apply your conventions to filter our types to be registered
            var interfacePairs = from t in bindTo.Where(x => x.IsInterface)
                                 let match = types.FirstOrDefault(x => x.Name ==     t.Name.Substring(1))
                                 where match != null
                                 select new Pair { To = t, From = match };
            var abstractPairs = new Pair[] {};


            // setup the generic form of the method to register the types
            var thisType = typeof(Program);
            var bindings = BindingFlags.Static | BindingFlags.Public;
            MethodInfo genericMethod = thisType.GetMethod("RegisterType", bindings);            

            // register all your types by executing the 
            // specialized generic form of the method
            foreach (var t in interfacePairs.Concat(abstractPairs))
            {
                Type[] genericArguments = new Type[] { t.To, t.From };
                MethodInfo method = genericMethod.MakeGenericMethod(genericArguments);
                method.Invoke(null, new object [] {});
            }

            Console.ReadKey();
        }

        public static void RegisterType<To, From>()
        {
            Console.WriteLine("Register { To: {0} From: {1} }", typeof(To), typeof(From));
        }

        // Test classes that should be picked up
        interface ITest { }
        class Test : ITest { }

        class Pair
        {
            public Type To { get; set; }
            public Type From { get; set; }
        }        
    }
}
Marven answered 25/12, 2008 at 5:46 Comment(2)
Not so much of a hack, as the source to CastleWindsor does something similar (be it, far more elegantly). A better idea for him would be to rip out the code used for Register(), and make an extension method off of the Unity container/Bucko
Just so I am clear you mean taking it out of Windsor then applying it to Unity? Sure why not! Ya... elegance? Maybe next project ; ).Marven
H
0

I just stumbled across this question looking for information on convention-based registration for Windsor and while this is a fairly old question I thought I'd leave an answer for others who may be looking for this sort of capabilities in Unity.

Last year I wrote a convention-based registration extension for Unity which you can read about here. The actual download is available on google code here. The basic usage is:

  _container
        .Using<IConventionExtension>()
        .Configure(x =>
            {
                x.Conventions.Add<InterfaceImplementionNameMatchConvention>();
                x.Assemblies.Add(Assembly.GetExecutingAssembly());
            })
        .Register();

There is also a ClosingTypeConvention for auto-registering open generic types:

  _container
                .Using<IConventionExtension>()
                .Configure(x =>
                    {
                        x.Conventions.Add(new ClosingTypeConvention(typeof (IRepository<>)));
                        x.Assemblies.Add(Assembly.GetExecutingAssembly());
                    })
                .Register();
Hulbard answered 2/3, 2010 at 22:42 Comment(0)
B
-1

AFAIK there's no way to do it in Unity. Unity is simply much less mature and worse architected container than Windsor, and as a result of that many things are harder/impossible with it.

Broddy answered 30/12, 2008 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.