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?
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
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With