/src/LinFu.Proxy/SerializableProxyBuilder.cs

http://github.com/philiplaureano/LinFu · C# · 175 lines · 128 code · 30 blank · 17 comment · 4 complexity · 3e46f6e6f9926858bda635d4cad74d14 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Runtime.Serialization;
  6. using LinFu.AOP.Interfaces;
  7. using LinFu.IoC.Configuration;
  8. using LinFu.Proxy.Interfaces;
  9. using LinFu.Reflection.Emit;
  10. using Mono.Cecil;
  11. using Mono.Cecil.Cil;
  12. using MethodAttributes = Mono.Cecil.MethodAttributes;
  13. namespace LinFu.Proxy
  14. {
  15. /// <summary>
  16. /// Represents a <see cref="ProxyBuilder" /> type that can create serializable proxy types.
  17. /// </summary>
  18. [Implements(typeof(IProxyBuilder), LifecycleType.OncePerRequest)]
  19. public class SerializableProxyBuilder : ProxyBuilder
  20. {
  21. /// <summary>
  22. /// Generates a proxy that forwards all virtual method calls
  23. /// to a single <see cref="IInterceptor" /> instance.
  24. /// </summary>
  25. /// <param name="originalBaseType">The base class of the type being constructed.</param>
  26. /// <param name="baseInterfaces">The list of interfaces that the new type must implement.</param>
  27. /// <param name="module">The module that will hold the brand new type.</param>
  28. /// <param name="targetType">The <see cref="TypeDefinition" /> that represents the type to be created.</param>
  29. public override void Construct(Type originalBaseType, IEnumerable<Type> baseInterfaces, ModuleDefinition module,
  30. TypeDefinition targetType)
  31. {
  32. var interfaces = new HashSet<Type>(baseInterfaces);
  33. if (!interfaces.Contains(typeof(ISerializable)))
  34. interfaces.Add(typeof(ISerializable));
  35. var serializableInterfaceType = module.ImportType<ISerializable>();
  36. if (!targetType.Interfaces.Contains(serializableInterfaceType))
  37. targetType.Interfaces.Add(serializableInterfaceType);
  38. // Create the proxy type
  39. base.Construct(originalBaseType, interfaces, module, targetType);
  40. // Add the Serializable attribute
  41. targetType.IsSerializable = true;
  42. var serializableCtor = module.ImportConstructor<SerializableAttribute>();
  43. var serializableAttribute = new CustomAttribute(serializableCtor);
  44. targetType.CustomAttributes.Add(serializableAttribute);
  45. ImplementGetObjectData(originalBaseType, baseInterfaces, module, targetType);
  46. DefineSerializationConstructor(module, targetType);
  47. var interceptorType = module.ImportType<IInterceptor>();
  48. var interceptorGetterProperty = (from PropertyDefinition m in targetType.Properties
  49. where
  50. m.Name == "Interceptor" &&
  51. m.PropertyType == interceptorType
  52. select m).First();
  53. }
  54. private static void DefineSerializationConstructor(ModuleDefinition module, TypeDefinition targetType)
  55. {
  56. var getTypeFromHandle = module.ImportMethod<Type>("GetTypeFromHandle",
  57. BindingFlags.Public | BindingFlags.Static);
  58. var parameterTypes = new[] {typeof(SerializationInfo), typeof(StreamingContext)};
  59. // Define the constructor signature
  60. var serializationCtor = targetType.AddDefaultConstructor();
  61. serializationCtor.AddParameters(parameterTypes);
  62. serializationCtor.Attributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName |
  63. MethodAttributes.RTSpecialName | MethodAttributes.Public;
  64. var interceptorInterfaceType = module.ImportType<IInterceptor>();
  65. var interceptorTypeVariable = serializationCtor.AddLocal<Type>();
  66. var body = serializationCtor.Body;
  67. body.InitLocals = true;
  68. var IL = serializationCtor.GetILGenerator();
  69. IL.Emit(OpCodes.Ldtoken, interceptorInterfaceType);
  70. IL.Emit(OpCodes.Call, getTypeFromHandle);
  71. IL.Emit(OpCodes.Stloc, interceptorTypeVariable);
  72. var defaultConstructor = module.ImportConstructor<object>();
  73. IL.Emit(OpCodes.Ldarg_0);
  74. IL.Emit(OpCodes.Call, defaultConstructor);
  75. // __interceptor = (IInterceptor)info.GetValue("__interceptor", typeof(IInterceptor));
  76. var getValue = module.ImportMethod<SerializationInfo>("GetValue");
  77. IL.Emit(OpCodes.Ldarg_0);
  78. IL.Emit(OpCodes.Ldarg_1);
  79. IL.Emit(OpCodes.Ldstr, "__interceptor");
  80. IL.Emit(OpCodes.Ldloc, interceptorTypeVariable);
  81. IL.Emit(OpCodes.Callvirt, getValue);
  82. IL.Emit(OpCodes.Castclass, interceptorInterfaceType);
  83. var setInterceptor = module.ImportMethod<IProxy>("set_Interceptor");
  84. IL.Emit(OpCodes.Callvirt, setInterceptor);
  85. ;
  86. IL.Emit(OpCodes.Ret);
  87. }
  88. private static void ImplementGetObjectData(Type originalBaseType, IEnumerable<Type> baseInterfaces,
  89. ModuleDefinition module, TypeDefinition targetType)
  90. {
  91. var getObjectDataMethod = (from MethodDefinition m in targetType.Methods
  92. where m.Name.Contains("ISerializable.GetObjectData")
  93. select m).First();
  94. var body = getObjectDataMethod.Body;
  95. body.Instructions.Clear();
  96. body.InitLocals = true;
  97. var IL = getObjectDataMethod.GetILGenerator();
  98. var proxyInterfaceType = module.ImportType<IProxy>();
  99. var getTypeFromHandle = module.ImportMethod<Type>("GetTypeFromHandle",
  100. BindingFlags.Public | BindingFlags.Static);
  101. var proxyObjectRefType = module.ImportType<ProxyObjectReference>();
  102. var setType = module.ImportMethod<SerializationInfo>("SetType",
  103. BindingFlags.Public | BindingFlags.Instance);
  104. var getInterceptor = module.ImportMethod<IProxy>("get_Interceptor");
  105. IL.Emit(OpCodes.Ldarg_1);
  106. IL.Emit(OpCodes.Ldtoken, proxyObjectRefType);
  107. IL.Emit(OpCodes.Call, getTypeFromHandle);
  108. IL.Emit(OpCodes.Callvirt, setType);
  109. // info.AddValue("__interceptor", __interceptor);
  110. var addValueMethod = typeof(SerializationInfo).GetMethod("AddValue",
  111. BindingFlags.Public | BindingFlags.Instance,
  112. null,
  113. new[] {typeof(string), typeof(object)},
  114. null);
  115. var addValue = module.Import(addValueMethod);
  116. IL.Emit(OpCodes.Ldarg_1);
  117. IL.Emit(OpCodes.Ldstr, "__interceptor");
  118. IL.Emit(OpCodes.Ldarg_0);
  119. IL.Emit(OpCodes.Castclass, proxyInterfaceType);
  120. IL.Emit(OpCodes.Callvirt, getInterceptor);
  121. IL.Emit(OpCodes.Callvirt, addValue);
  122. IL.Emit(OpCodes.Ldarg_1);
  123. IL.Emit(OpCodes.Ldstr, "__baseType");
  124. IL.Emit(OpCodes.Ldstr, originalBaseType.AssemblyQualifiedName);
  125. IL.Emit(OpCodes.Callvirt, addValue);
  126. var baseInterfaceCount = baseInterfaces.Count();
  127. // Save the number of base interfaces
  128. var integerType = module.ImportType<int>();
  129. IL.Emit(OpCodes.Ldarg_1);
  130. IL.Emit(OpCodes.Ldstr, "__baseInterfaceCount");
  131. IL.Emit(OpCodes.Ldc_I4, baseInterfaceCount);
  132. IL.Emit(OpCodes.Box, integerType);
  133. IL.Emit(OpCodes.Callvirt, addValue);
  134. var index = 0;
  135. foreach (var baseInterface in baseInterfaces)
  136. {
  137. IL.Emit(OpCodes.Ldarg_1);
  138. IL.Emit(OpCodes.Ldstr, string.Format("__baseInterface{0}", index++));
  139. IL.Emit(OpCodes.Ldstr, baseInterface.AssemblyQualifiedName);
  140. IL.Emit(OpCodes.Callvirt, addValue);
  141. }
  142. IL.Emit(OpCodes.Ret);
  143. }
  144. }
  145. }