7
votes

PCLs do work well in MonoTouch and MonoDroid.

However, sometimes, when I use a variable to reference a Type in a PCL, and then I try to use that same reference in a MonoX client, then the compiler fails with a message like:

The type 'System.Collections.Specialized.INotifyCollectionChanged' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes'.

The problem here is that in MonoDroid my System.Collections.Specialized.INotifyCollectionChanged PCL is provided in a shim Type Forwarding DLL - like https://github.com/slodge/MvvmCross/tree/vnext/Cirrious/System.Windows - and obviously that DLL cannot be signed using Microsoft's Private Key.

Some more info:

  • This is commonly seen for interfaces like ICommand and INotifyCollectionChanged
  • It only seems to occur in .exe projects (libraries somehow work OK)
  • I'm mainly testing/building in VS2010 and VS2012
  • some more at: https://github.com/slodge/MvvmCross/issues/41

Can anyone suggest any way to resolve this? e.g. is there a way of turning the strong assembly naming protection off?

I think this is needed if PCLs are to be truly Portable outside of Microsoft shipped .Net implementations?

2

2 Answers

2
votes

From an admin VS command prompt, you can run this:

sn -Vr *,7cec85d7bea7798e

This will skip strong name verification for any assembly with 7cec85d7bea7798e as the public key token. Then you should be able to delay sign your shim DLL with that key. I think you can use sn -pc to extract the public portion of a key from a DLL in order to use it for delay signing.

This should allow you to compile using the shims. Of course, it also needs to work at runtime. I think that MonoTouch and MonoDroid don't actually validate the strong name keys for assemblies, so it will just work. If they do do this validation, then I don't think there's much you can do. In that case either Mono would need to make some changes to support these type references or ignore the key for the shims, or Microsoft would need to provide signed versions of the shim DLLs you can use.

Note that I'm not a security expert so I don't know what kind of security impact disabling strong name validation on your machine for these Microsoft keys might have. I don't think there will be any significant impact...


Detailed follow up from Daniel:

I think this is what you need to do to get around the type sharing / strong name signing issues for portable libraries on Mono:

-> Extract the public key of System.Windows.dll, and put it in the project directory for the Droid System.Windows project:

 Sn –e "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\Profile\Profile104\System.Windows.dll" system_windows.snk

-> Modify the Droid system.windows project to delay-sign using the extracted key. Put the following in a PropertyGroup in the csproj file:

<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>system_windows.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>

-> Change the assembly version of the Droid System.Windows project (in AssemblyInfo.cs) to:

2.0.5.0 

In my testing, I didn’t seem to need to disable strong name verification. So I don’t think it will present any extra barriers for newbies – once you have these changes made they’ll just need to get your code and it will build correctly.

However, if you do run into problems, try running the following from an admin VS command prompt:

 sn -Vr *,7cec85d7bea7798e 

Let me know how this works!

Thanks,

Daniel

-1
votes

I have similar problem in my project where I have PCL for .Net 4.5, Windows Phone 8, WinRT, MonoTouch and MonoDroid, when I try to build MonoDroid or MonoTouch project errors are following:

*Error 1 The type 'System.Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

Error 2 The type 'System.Enum' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

I have done suggested command (sn -Vr *,b03f5f7f11d50a3a), but it didn't help. I am using the following profile:

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile78