Partial Trust, Windows Azure & Pluggable Serializers

by Gael Fraiteur on 03 Nov 2008

Would I be a perfect .NET developer if I did not blog about Windows Azure? I let the response to your own judgment, but even if you don't agree on that statement read on.

If you try to deploy a PostSharp-enabled assembly into the Development Fabric, you will probably get the following exception:

[SecurityException: Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.]
   System.Runtime.Serialization.Formatters.Binary.ObjectReader.CheckSecurity(ParseRecord pr) +10107255
   System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseArray(ParseRecord pr) +155
   System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseObject(ParseRecord pr) +151
   System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadArray(BinaryHeaderEnum binaryHeaderEnum) +581
   System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run() +283
   System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) +559
   System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) +326
   System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) +33
   PostSharp.Laos.Serializers.BinaryLaosSerializer.Deserialize(Stream stream) in BinaryLaosSerializer.cs:46
   PostSharp.Laos.LaosSerializer.Deserialize(Assembly assembly, String resourceName) in LaosSerializer.cs:68
   ~PostSharp~Laos~Implementation..cctor() +365

Don't panic, it is not the end of the story.

Clearly, there is a security exception. Looking at the stack trace, you see that the exception occurs in the BinaryFormatter.Deserialize. Indeed, the binary formatter requires full trust and... code running inside Windows Azure is only partially trusted.

I could have written the same for code running inside SQL Server 2005, but it's less hyped: very often, when your code is hosted, it is not granted full trust.

Pluggable Serializers

If you are new to PostSharp, you may wonder why BinaryFormatter is invoked at runtime. In fact, at build time, aspects are instantiated and serialized into a binary stream. This stream is stored in a managed resource in the assembly and deserialized at runtime. That's why the binary formatter is invoked.

Fortunately, PostSharp 1.5 CTP 2 comes with a new feature called pluggable serializers. Before, you had no choice: aspects were always serialized using the BinaryFormatter. It is the best tool for the job for most situations, but, as you can see here with partial-trust scenarios, it is not always possible to use it.

But there are other serializers in .NET, isn't it? So why not to use them? That's exactly the idea behind pluggable serializers: you can now choose the serializer used to to serialize aspects at build time and deserialize them at rutime.

PostSharp 1.5 comes with three serializers: BinaryLaosSerializer (relying on BinaryFormatter), XmlLaosSerializer (relying on XmlSerializer) and StateBagSerializer (requiring manual implementation in all classes, see documentation). All implement the abstract class PostSharp.Laos.Serializer; if you need another serializer, you can develop your.

Once you have selected a serializer, you should tell PostSharp to use it for your aspect. This is done by applying the custom attribute LaosSerializerAttribute to your aspect class. For instance:

[LaosSerializer(typeof(XmlLaosSerializer))]
public class SomeAspect : OnMethodBoundaryAspect
{ 
[XmlElement] public string Name;
public override void OnEntry(MethodExecutionEventArgs eventArgs) { } }

Since this serializer does not require full trust... it simply works in Windows Azure!

Why do I need a serializer, anyway?

Excellent remarks. Serializers are good when there there is some non-trivial state to be stored. But if your aspect is an isolated custom attribute with some public fields or public properties, it is far better to instantiate the attribute at runtime using the values provided to construct the custom attribute.

For instance, if a custom attribute instance is defined by:

[SomeAspect(Name = "Hello")]

It would be much better (faster and byte-wise more compact) to create the aspect using the following code:

SomeAspect instance = new SomeAspect { Name = "Hello" };

This is exactly what happens if you use the custom attribute LaosSerializerAttribute and pass null to the constructor parameter. The aspect won't be serialized; it will be instantiated and initialized at runtime by some auto-generated code. And this is actually the way aspects for Compact Framework and Silverlight work.

So remember: even if you don't write partially trusted code, you can still use the "null serializer" to improve the size and performance of your assemblies.

Happy PostSharping!

-gael