11

I was trying to use Unity 2.0 beta 2 for Silverlight in my Windows Phone 7 project and I kept getting this crash:

Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.DynamicMethodConstructorStrategy() + 0x1f bytes

Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.DynamicMethodConstructorStrategy() + 0x1f bytes   mscorlib.dll!System.Reflection.RuntimeConstructorInfo.InternalInvoke(System.Reflection.RuntimeConstructorInfo rtci = {System.Reflection.RuntimeConstructorInfo}, System.Reflection.BindingFlags invokeAttr = Default, System.Reflection.Binder binder = null, object parameters = {object[0]}, System.Globalization.CultureInfo culture = null, bool isBinderDefault = false, System.Reflection.Assembly caller = null, bool verifyAccess = true, ref System.Threading.StackCrawlMark stackMark = LookForMyCaller)  
mscorlib.dll!System.Reflection.RuntimeConstructorInfo.InternalInvoke(object obj = null, System.Reflection.BindingFlags invokeAttr = Default, System.Reflection.Binder binder = null, object[] parameters = {object[0]}, System.Globalization.CultureInfo culture = null, ref System.Threading.StackCrawlMark stackMark = LookForMyCaller) + 0x103 bytes 
mscorlib.dll!System.Activator.InternalCreateInstance(System.Type type = {Name = "DynamicMethodConstructorStrategy" FullName = "Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy"}, bool nonPublic = false, ref System.Threading.StackCrawlMark stackMark = LookForMyCaller) + 0xf0 bytes mscorlib.dll!System.Activator.CreateInstance() + 0xc bytes 
Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.ObjectBuilder2.StagedStrategyChain.AddNew(Microsoft.Practices.Unity.ObjectBuilder.UnityBuildStage stage = Creation) + 0x1d bytes    
Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.Unity.UnityDefaultStrategiesExtension.Initialize() + 0x6c bytes   
Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.Unity.UnityContainerExtension.InitializeExtension(Microsoft.Practices.Unity.ExtensionContext context = {Microsoft.Practices.Unity.UnityContainer.ExtensionContextImpl}) + 0x31 bytes  
Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.Unity.UnityContainer.AddExtension(Microsoft.Practices.Unity.UnityContainerExtension extension = {Microsoft.Practices.Unity.UnityDefaultStrategiesExtension}) + 0x1a bytes 
Microsoft.Practices.Unity.Silverlight.dll!Microsoft.Practices.Unity.UnityContainer.UnityContainer() + 0xf bytes 

Thinking I could resolve it I've tried a few things but to no avail.

Turns out that this is a rather fundamental problem and my assumption that Windows Phone 7 is Silverlight 3 + Some other stuff is wrong. This page describes the differences between Mobile Silverlight and Silverlight 3.

Of particular interest is this:

The System.Reflection.Emit namespace is not supported in Silverlight for Windows Phone.

This is precisely why Unity is crashing on the phone, DynamicMethodConstructorStrategy class uses System.Reflection.Emit quite extensively...

So the question is, what alternative to Unity is there for Windows Phone 7?

Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
  • 1
    Report that as a bug to Unity team. Silverlight and Windows Phone should have same API (except windows phone has a few extra things). – CVertex May 03 '10 at 05:29
  • 1
    This is not really a bug. There are massive differences between Silverlight3 and Windows Phone Silverlight. The unity team is aware of it: http://unity.codeplex.com/Thread/View.aspx?ThreadId=207143 Perhaps they release a version with Phone support. – Igor Zevaka May 03 '10 at 06:00

6 Answers6

7

So, in the spirit of answering my own questions, I've put together a simple DI container (using Activator.CreateInstance for instantiating things). All this does is support type registrations and instance registrations.

Seems to be doing the job. Will worry about performance later.

public class DuplicateRegistrationException : Exception {
    public DuplicateRegistrationException() { }
    public DuplicateRegistrationException(string message) : base(message) { }
    public DuplicateRegistrationException(string message, Exception inner) : base(message, inner) { }
}

public interface IDIContainer {
    void Register<TIntf, TClass> () where TIntf: class where TClass : TIntf;
    TIntf Resolve<TIntf>() where TIntf : class;
    void RegisterInstance<TIntf>(TIntf instance);
}

public class DIContainer :  IDIContainer{

    Dictionary<Type, Type> m_TypeRegistrations;
    Dictionary<Type, object> m_InstanceRegistrations;

    public DIContainer() {
        m_TypeRegistrations = new Dictionary<Type, Type>();
        m_InstanceRegistrations = new Dictionary<Type, object>();
    }

    #region IDIContainer Members

    public void Register<TIntf, TClass>()
        where TIntf : class
        where TClass : TIntf {
            if(DoesRegistrationExist<TIntf>())
                throw new DuplicateRegistrationException("Can only contain one registration per type");
            m_TypeRegistrations.Add(typeof(TIntf), typeof(TClass));
    }

    public TIntf Resolve<TIntf>() where TIntf : class {
        return Resolve(typeof(TIntf)) as TIntf;
    }

    private object Resolve(Type type) {
        if(!m_TypeRegistrations.ContainsKey(type)) {
            if(!m_InstanceRegistrations.ContainsKey(type))
                throw new NotSupportedException("Cannot find registration for type " + type.FullName + ".");
            else
                return m_InstanceRegistrations[type];
        } else {
            var createdType = m_TypeRegistrations[type];

            ConstructorInfo[] constructors = createdType.GetConstructors();
            ConstructorInfo mostSpecificConstructor = null;
            foreach(var c in constructors) {
                if(mostSpecificConstructor == null || mostSpecificConstructor.GetParameters().Length < c.GetParameters().Length) {
                    mostSpecificConstructor = c;
                }
            }

            List<object> constructorParameters = new List<object>();
            foreach(var a in mostSpecificConstructor.GetParameters()) {
                constructorParameters.Add(Resolve(a.ParameterType));
            }

            return Activator.CreateInstance(createdType, constructorParameters.ToArray());
        }
    }

    private bool DoesRegistrationExist<T>() {
        return m_InstanceRegistrations.ContainsKey(typeof(T)) || m_TypeRegistrations.ContainsKey(typeof(T));
    }

    public void RegisterInstance<TIntf>(TIntf instance) {
        if(DoesRegistrationExist<TIntf>()) {
            throw new DuplicateRegistrationException("Can only contain one registration per type");
        }
        m_InstanceRegistrations.Add(typeof(TIntf), instance);
    }


    #endregion
Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
  • Activator.CreateInstance is resource intensive. I would recommend using Funq as an alternative method. Watch the first screen cast series from "http://blogs.clariusconsulting.net/kzu/funq-screencast-series-on-how-to-building-a-di-container-using-tdd/" and you'll see. – Evan Larsen May 10 '11 at 17:40
  • This post was made about a month after WP7 SDK came out, at which point there were no acceptable WP7 DI containers. Having said that, i didn't know compiling expressions to lambdas is allowed under WP7 sandbox. – Igor Zevaka May 11 '11 at 01:00
5

Funq has been in development for over a year and now has a 1.0 release. It's designed to be fast and run under Compact Framework and Windows Phone 7. Another big advantage is that the author has done great a screencast series explaining its development process using TDD which is very informative!

As an aside, the most recent performance tests that I can find are from March 2009 showing it beating the pants off Unity, Autofac, Ninject, and StructureMap. I'm trying to locate more recent tests and will update this post if I do.

Alex Angas
  • 59,219
  • 41
  • 137
  • 210
2

If you cannot find an IOC container that works on Windows Phone 7 (and I wouldn't be surprised you cannot) then I'd suggest going with a different DI strategy.

Brent Arias
  • 29,277
  • 40
  • 133
  • 234
  • Thanks for that. The article mirrors a lot of the thoughts I had about using a DI container. Unfortunately I need a solution with slightly higher level of automagicness to create very loosely coupled app (some parts of which are generated). I kinda agree, that with heavy use of `System.Reflection` DI frameworks might be fundamentally stuffed on WP7. – Igor Zevaka May 03 '10 at 05:41
  • Thanks, this is a great article. – nlawalker Aug 28 '11 at 16:00
2

I just started putting together a Windows Phone 7 Extension Tools project on codeplex. The current version checked in supports IoC with implicit DI along with the Common Service Locator to allow complete abstraction of your code and the container they use.

Check it out over at: http://wp7.codeplex.com

Cheers, Simon Hart

Simon Hart
  • 31
  • 2
1

The OpenNETCF.IoC framework works on Windows desktop, Mono, Windows Mobile, Windows Phone 7 and MonoTouch. I'm a fan of code reuse.

It's modelled after the SCSF/CAB (in object model, not crappy perf), so many of those tutorials are valid and you can leverage existing knowledge and code assets.

ctacke
  • 66,480
  • 18
  • 94
  • 155
1

Despite Mark Seeman says "the world doesn’t need yet another container" in his excellent book "Dependency Injection in .NET", I decided to implement my own DI container for WP7 which provides the major DI features:

  • object composition
  • lifetime management
  • interception which allows you to aspect-oriented programming approaches

The container is the part of PhoneCore Framework, which you can find here: http://phonecore.codeplex.com

Ilya Builuk
  • 2,189
  • 2
  • 16
  • 10