|
|
|
Community Member
|
|
Hi. First I describe the problem. I have a silverlight assembly, which I instrument using PostSharp.Core (not Laos) attributes. However, the build fails with this exception:
PostSharp.CodeModel.BindingException occurred Message="Cannot find a method named 'GetEnumerator' with signature '() : [mscorlib]System.Collections.Generic.IEnumerator`1<!0>' in scope 'Wintellect.PowerCollections.CollectionBase`1' (module = 'PowerCollections.dll')." Source="PostSharp.Core" StackTrace: at PostSharp.CodeModel.Collections.MethodDefDeclarationCollection.GetMethod(String name, IMethodSignature signature, BindingOptions bindingOptions) in C:\Dev\3rd_party\PostSharp\Core\PostSharp.Core\CodeModel\MethodDefDeclaration.cs:line 1503 InnerException:
After wasting several hours investigating the issue, here are my findings. - Our silverlight assembly along with all its dependencies lies in $(DEV)\windows\bin\Silverlight\Debug folder. This folder also includes the silverlight build of PostSharp.Public.dll and our aspects dll (silverlight build, of course). One of the dependencies is a silverlight build of PowerCollections.dll. These dependencies are 3rd party dlls, which were copied to the target folder from the $(DEV)\3rd_party\bin\Silverlight\Debug folder, which contains the silverlight builds of the relevant 3rd party libraries. - PostSharp-1.5.targets along with all the required PostSharp assemblies lie in $(DEV)\3rd_party\bin\DotNet\Debug folder. This same folder also contains a .NET build of PowerCollections.dll, which only makes sense, because this folder contains all the .NET builds of our 3rd party libraries, where PostSharp and PowerCollections are examples of such. - When PostSharp creates a map of used types, it loads PowerCollections.dll from the $(DEV)\3rd_party\bin\DotNet\Debug folder, despite the fact that the target is a silverlight build and there is the correct version of PowerCollections.dll in the target folder!!! If I delete this file, then PostSharp loads the correct version from the target folder - $(DEV)\windows\bin\Silverlight\Debug.
It looks like when loading dependencies, PostSharp prefers its home folder over the target folder and if there are different builds of the same library in both places, it loads the one from the home folder. This wrecks havoc in our scenario.
A very important note - different platform builds of the same library have identical assembly name - the same version, public key token, etc... So, technically, PostSharp may decide that the two versions are equivalent, although it can deduce pretty fast that one is a .NET build and another is a Silverlight build.
Now, one may say "what the hack, make the two builds differ in version and/or public key, like mscorlib does - .NET is 2.0.0.0 and Silverlight is 2.0.5.0, so that the different platform builds have different versions".
Sounds like the right thing to do, but this may not be as trivial as it seems. So, I would like to know whether it is possible to change PostSharp, so that it starts looking for referenced assemblies in the instrumentation target folder, rather than in its own home folder.
Thanks.
|
|
|
|
|
Gael Fraiteur
SharpCrafters
|
|
It's not possible to change the order of directories in the search path, but something you may try (since I see you compile PostSharp yourself) is to edit the file AssemblyLocator.cs. You'll see:
// 3. Look in directories containing the assemblies that are loaded in the AppDomain foreach ( string directory in priorityDirectories ) { string location = ProbeDirectory( directory, requestedAssemblyName, "this directory contains an assembly that has already been loaded" ); if (location != null) return location; } // 4. Look in the list of files foreach ( string file in this.files ) { string location = ProbeFile(file, requestedAssemblyName, "this file was explicitely added to the search path"); if (location != null) return location; }
Basically, invert points 3 and 4. The list of files is actually the list of references received by the C# compiler, so logically they should be processed by higher priority.
Unfortunately, I cannot make the change in PostSharp 1.5 since it may break something for some customers. I will consider doing the change in PostSharp 2.0 since it's still beta.
-gael
|
|
|
|
|
Gael Fraiteur
SharpCrafters
|
|
|
<!-- m --><a class="postlink" href="http://www.postsharp.org/tracker/view.php?id=463">http://www.postsharp.org/tracker/view.php?id=463</a><!-- m -->
|
|
|
|
|
Community Member
|
|
Hi Gael.
Why do you examine AppDomain.CurrentDomain.GetAssemblies() when trying to match the given assembly reference? After all, these are always .NET assemblies, because msbuild runs on the full .NET platform. However, the instrumented assembly may be Silverlight, Mono, Compact Framework, God knows what...
As I see it, this is a bug and its severity is not minor, but I may be wrong in reading this picture. Can you share the rationale, please?
Thanks.
|
|
|
|
|
Community Member
|
|
Hi Gael. Another question. Observe the following piece of code from the AssemblyLocator.FindAssembly method:
// 2. Look in GAC string gacLocation = Platform.Current.FindAssemblyInCache( assemblyName ); if ( gacLocation != null ) { return gacLocation; }
My instrumented assembly is built using Silverlight platform, but Platform.Current returns
{PostSharp.PlatformAbstraction.DotNet.DotNet20Platform}
Of course, after all this is indeed the current platform. But the platform to search in GAC should be the Silverlight platform, not the current one. Again, I miss the rationale here and think this is a bug.
|
|
|
|
|
Gael Fraiteur
SharpCrafters
|
|
|
Exact; there should not be a GAC lookup in that case.
|
|
|
|
|
Gael Fraiteur
SharpCrafters
|
|
|
<!-- m --><a class="postlink" href="http://www.postsharp.org/tracker/view.php?id=465">http://www.postsharp.org/tracker/view.php?id=465</a><!-- m -->
|
|
|
|
|
Community Member
|
|
Observing the code of the GetAssemblyNameForFrameworkVariant method I deduce that PostSharp.Public and PostSharp.Laos must have identical public keys on all the platforms. In fact the rules are rather strict - the full names of the respective assemblies of the different platform builds must differ only in their short name, where the platform code is appended to the short name, So that PostSharp.Public becomes PostSharp.Public.SL.dll on Silverlight, having exactly the same public key as PostSharp.Public.dll for the full framework.
Am I right?
Thanks.
|
|
|
|
|
Community Member
|
|
BTW, how should I fix the FindAssemblies method in the meantime? I need it to work correctly both for the full .NET platform and Silverlight. Right now I have just commented out the regions 0, 2 and 3.
Thanks.
|
|
|
|
|
Gael Fraiteur
SharpCrafters
|
|
|
That PostSharp.Public becomes PostSharp.Public.SL.dll on Silverlight, having exactly the same public key as PostSharp.Public.dll for the full framework.
Am I right?
Yes, it's kind of a hack, but it's how it works currently (this is actually just a utility method allowing to map a System.Type to an ITypeSignature).
|
|
|
|
|
Gael Fraiteur
SharpCrafters
|
|
|
BTW, how should I fix the FindAssemblies method in the meantime? I need it to work correctly both for the full .NET platform and Silverlight. Right now I have just commented out the regions 0, 2 and 3.
0 and 2 should only be skipped if this.Domain.ReflectionDisabled == true. 3 and 4 should be swapped.
|
|
|
|
|
Community Member
|
|
Thanks, Gael. I will do so.
|
|
|
|