SharpCrafters Forum – Deserialization problem

SharpCrafters Support Forum

        


Deserialization problem Expand / Collapse
Author
Message
Posted 3/8/2010 2:25:28 PM


Community Member
Dear SharpCrafters!
First, I'd like to thank you for your product, I hope that we'll be 2.0 customers soon. Yet we use v1.5 in our prototype and ran into a serious problem...

We used Laos to define some aspects, for example some support for the famous INotifyPropertyChanged interface. The application which will be delivered soon, was built uppon these aspects. Everything worked fine until we tried to insert our built assemblies as plug-ins into a framework application using reflection to load the plug-ins.

The CreateInstance method of a class which has aspect defined throws TargetInvocationException. All of the referenced dlls are loaded. It seems that the <>AspectsImplementationDetails_1 cannot deserialize the aspects from the classes contructor, if the postsharped dlls aren't in the executable directory. Could you help us please?

Some additional information:
- We use Windows 7 with .NET FW 3.5.
- The deserialization fails on the <>AspectsImplementationDetails_1() method when it tries to deserialize the aspect array based on the resource stream.
- Inner exceptions:
(1) TypeInitializationException: "The type initializer for '<>AspectsImplementationDetails_1' threw an exception."
(2) FileNotFoundException: "Could not load file or assembly 'X, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified." (It is loaded, but physically in another directory. The type we trying to instantiate located in the same assembly.)

=== Pre-bind state information ===
LOG: User = ...
LOG: DisplayName = X, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///E:/.../bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///E:/.../bin/Debug/X.DLL.
LOG: Attempting download of new URL file:///E:/.../bin/Debug/X/X.DLL.
LOG: Attempting download of new URL file:///E:/.../bin/Debug/X.EXE.
LOG: Attempting download of new URL file:///E:/.../bin/Debug/X/X.EXE.

Best regards: Kornél Kátai from Budapest
Post #4103
Posted 3/8/2010 5:22:35 PM


Community Member
I think I've just found the cause - based on http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/e5f0c371-b900-41d8-9a5b-1052739f2521, the mscorlib deserializer doesn't check the assemblies currently loaded into the application domain, only the executable directory (and some more useless places). There is a workaround: overriding the serialization binder's BindToType method to check the app. domain.

Maybe you also should insert these few lines of code into your BinaryLaosSerializationBinder class to avoid problems when the postsharped dll and the executable are not in the same directory.

Best wishes: Kornél Kátai
Post #4104
Posted 3/8/2010 6:44:00 PM


Gael Fraiteur

SharpCrafters
Glad to see you found your way
Post #4105
Posted 3/9/2010 3:17:07 PM


Community Member
Dear Gael,
Well, I found the reason causing the problem (still exists in PostSharp v2) and the solution. So, I downloaded the source of v1.5, followed the instructions in the attached html files, but I constantly having versioning problems, public key conflicts and stuff.

I removed the signing, replaced the dll -s in my applications, thought it'll work the same way it did so far - no luck. While the signing was on, it thrown exception runtime because of key mismatch, so I removed the delay - I couldn't build because of the snk, I removed and the postsharp doesn't do anything now.

I getting crazy, because I'm not familiar with this signing stuff and not an expert of the configurations of PostSharp neighter.

(I use PostSharp in the not-installed way, set individually for each affected projects as described in the ref. docs.)

Can I find a quick guide for dummies which describes the needed steps from downloading the sources to have a usable deploy? Unfortunatelly we're running out of time and reverting the aspects into the redundant solutions would not be a lucky step, because this should be the way we'd like to go, but we need to be able to use the postsharped assemblies from locations other than the directory of the main executable.

The needed changes however are minor and would easily help in both versions. Is there any chance you'll deploy it in the near future?

Thank you for any help!

Best wishes: Kornél Kátai
Post #4125
Posted 3/9/2010 7:09:48 PM


Gael Fraiteur

SharpCrafters
There's no need to change the source code.

You can override the class BinaryAspectSerializationBinder and set the static property AspectSerializer.Binder (in PostSharp 2.0). You just have to set the property before any class using an aspect is used.

Alternatively, you can do your own AspectSerializer and specify it using (for instance):

[OnMethodBoundaryAspectConfiguration(SerializerType=typeof(MyAspectSerializer))]

I won't make additional efforts to make PostSharp easy to build from source. First, many have been successful in it. Second, PostSharp 2.0 is no longer open source.

I'll see if I can integrate the trick you suggest in PostSharp 2.0.
Post #4126
Posted 3/12/2010 10:32:59 AM


Gael Fraiteur

SharpCrafters
Hi Kornél,

I'm reviewing your post to see if I can improve PostSharp in some way.

I'm afraid I did not understand fully your suggestion. Are you suggesting that PostSharp should try to load an assembly using Assembly.Load when the requested assembly is not already loaded in the AppDomain?

Did you manage to do it the way I suggested and was it an acceptable solution?

Thanks.

-gael
Post #4153
Posted 3/12/2010 1:34:25 PM


Community Member
Dear Gael,
I had no luck with this approach, but found a more generic solution. My suggestion was to enhance the aspect serializer to check assemblies currently loaded into the application domain. For example I have a framework which loads plug-ins and their referenced dlls into the app. domain and tries to instantiate them via Activator. The serialized aspects couldn't be deserialized because the serializer always tries to directly load the referenced dlls from the executable directory (or from GAC) and doesn't care if they are loaded already.

I suppose this design was introduced to handle dll hell or something.

However I've implemented my own aspect serializer class and set as you suggested, but unfortunately the deserializer tries to load the assemblies one more time, in the method DoFixups (mscorelib), which doesn't use the binder I've introduced in the serializer (which actually would do everything fine).

The solution was to set an event handler on AppDomain.CurrentDomain.AssemblyResolve and do the trick there. This also works on 1.5, but everyone have to implement it separately and before any aspect using class loaded.

The code I use looks like this (I intentionally do not handle version checking, everyone may update it if needed):


static Service()
       {
           AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
       }

       static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
       {
           Assembly result = null;

           string shortAssemblyName = args.Name.Split(',')[0];
           foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
               if (shortAssemblyName == assembly.FullName.Split(',')[0])
               {
                   result = assembly;
                   break;
               }

           return result;
       }


Best regards: Kornél
Post #4161
Posted 3/12/2010 1:40:56 PM


Gael Fraiteur

SharpCrafters
Thanks - I also think it's possible to have a generic solution.

I suspect your assembly is loaded using Assembly.LoadFrom. This is typical for plugins or COM services. Am I correct?

-gael
Post #4162
Posted 3/12/2010 1:55:24 PM


Community Member
Yes, you are correct.
Post #4165
« Prev Topic | Next Topic »


All times are GMT +1:00, Time now is 11:42am

Powered By InstantForum.NET v4.1.4 © 2010
Execution: 0.205. 8 queries. Compression Disabled.