PageRenderTime 73ms CodeModel.GetById 40ms app.highlight 13ms RepoModel.GetById 17ms app.codeStats 0ms

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