Beispiel #1
0
        // Registers surrogates with all of the operations on the specified contract. These surrogates
        // take care of representing entities in the right shape based on TypeDescriptor extensions.
        private static void RegisterSurrogates(ContractDescription contractDesc, DomainServiceDescription domainServiceDescription)
        {
            // Cache the list of entity types and surrogate types.
            HashSet <Type> exposedTypes = new HashSet <Type>();
            Dictionary <Type, Tuple <Type, Func <object, object> > > exposedTypeToSurrogateMap = new Dictionary <Type, Tuple <Type, Func <object, object> > >();
            HashSet <Type> surrogateTypes = new HashSet <Type>();

            foreach (Type entityType in domainServiceDescription.EntityTypes)
            {
                exposedTypes.Add(entityType);
            }

            // Because complex types and entities cannot share an inheritance relationship, we can add them to the same surrogate set.
            foreach (Type complexType in domainServiceDescription.ComplexTypes)
            {
                exposedTypes.Add(complexType);
            }

            foreach (Type exposedType in exposedTypes)
            {
                Type surrogateType = DataContractSurrogateGenerator.GetSurrogateType(exposedTypes, exposedType);
                Func <object, object> surrogateFactory             = (Func <object, object>)DynamicMethodUtility.GetFactoryMethod(surrogateType.GetConstructor(new Type[] { exposedType }), typeof(Func <object, object>));
                Tuple <Type, Func <object, object> > surrogateInfo = new Tuple <Type, Func <object, object> >(surrogateType, surrogateFactory);
                exposedTypeToSurrogateMap.Add(exposedType, surrogateInfo);
                surrogateTypes.Add(surrogateType);
            }

            DomainServiceSerializationSurrogate surrogate = new DomainServiceSerializationSurrogate(domainServiceDescription, exposedTypeToSurrogateMap, surrogateTypes);

            // Register our serialization surrogate with the WSDL exporter.
            DomainServiceWsdlExportExtension wsdlExportExtension = contractDesc.Behaviors.Find <DomainServiceWsdlExportExtension>();

            if (wsdlExportExtension == null)
            {
                wsdlExportExtension = new DomainServiceWsdlExportExtension(surrogate);
                contractDesc.Behaviors.Add(wsdlExportExtension);
            }

            // Register our serialization surrogate with the actual invoke operations.
            foreach (OperationDescription op in contractDesc.Operations)
            {
                foreach (Type surrogateType in surrogateTypes)
                {
                    op.KnownTypes.Add(surrogateType);
                }

                DataContractSerializerOperationBehavior dataContractBehavior = op.Behaviors.Find <DataContractSerializerOperationBehavior>();
                if (dataContractBehavior == null)
                {
                    dataContractBehavior = new DataContractSerializerOperationBehavior(op);
                    op.Behaviors.Add(dataContractBehavior);
                }
                dataContractBehavior.DataContractSurrogate = surrogate;
            }
        }
        // Emit a surrogate property for a virtual property (a property that doesn't exist on the physical CLR type).
        // The PropertyDescriptor for each virtual property is initialized in the type initializer of a surrogate type.
        // The surrogate code we'll generate will look like this:
        // public <PropertyType> <PropertyName> {
        //     get {
        //         // For reference types.
        //         return (<PropertyType>)$<PropertyName>.GetValue(_$wrapper);
        //
        //         // For value types.
        //         object value = $<PropertyName>.GetValue(_$wrapper);
        //         if (value == null) {
        //             return default(value);
        //         }
        //         return (<PropertyType>)value;
        //
        //         // For Binary.
        //         Binary value = (Binary)$<PropertyName>.GetValue(_$wrapper);
        //         if (value == null) {
        //             return null;
        //         }
        //         return value.ToArray();
        //     }
        //     set {
        //         if (value == null) {
        //             return;
        //         }
        //
        //         // For normal types.
        //         $<PropertyName>.SetValue(_$wrapper, value);
        //
        //         // For value types.
        //         $<PropertyName>.SetValue(_$wrapper, (object)value);
        //
        //         // For Binary.
        //         Binary valueToStore;
        //         if (value == null) {
        //             valueToStore = null;
        //         }
        //         else {
        //             valueToStore = new Binary(value);
        //         }
        //         $<PropertyName>.SetValue(_$wrapper, valueToStore);
        //     }
        // }
        private static void EmitAttachedProperty(TypeBuilder typeBuilder, FieldInfo wrapperField, Lazy <ILGenerator> typeInitializerFactory, PropertyDescriptor pd, string name)
        {
            // private static PropertyDescriptor $property;
            FieldBuilder propertyDescFieldBuilder = typeBuilder.DefineField("$" + name, typeof(PropertyDescriptor), FieldAttributes.Private | FieldAttributes.Static);

            EmitPropertyInitializer(propertyDescFieldBuilder, typeInitializerFactory, name);

            Type            propertyType    = SerializationUtility.GetClientType(pd.PropertyType);
            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.None, propertyType, null);

            CustomAttributeBuilder dataMemberAtt = DataContractSurrogateGenerator.GetDataMemberAttributeBuilder(
                pd.Attributes[typeof(DataMemberAttribute)] as DataMemberAttribute);

            propertyBuilder.SetCustomAttribute(dataMemberAtt);

            // get {
            //     return $property.GetValue(_$wrapper);
            // }
            MethodBuilder getPropertyMethodBuilder = typeBuilder.DefineMethod("get_" + name, MethodAttributes.Public, propertyType, Type.EmptyTypes);
            ILGenerator   generator = getPropertyMethodBuilder.GetILGenerator();

            // Get the PropertyDescriptor.
            generator.Emit(OpCodes.Ldsfld, propertyDescFieldBuilder);

            // Push the wrapper object onto the stack. We'll use it as an argument for our
            // call to GetValue later on.
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, wrapperField);

            // PropertyDescriptor.GetValue(_$wrapper).
            generator.Emit(OpCodes.Callvirt, typeof(PropertyDescriptor).GetMethod("GetValue"));

            // Unbox/cast.
            DynamicMethodUtility.EmitFromObjectConversion(generator, pd.PropertyType);

            // Deal with client-server type conversions.
            if (propertyType != pd.PropertyType)
            {
                EmitToClientConversion(generator, pd.PropertyType, propertyType);
            }

            generator.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropertyMethodBuilder);

            MethodBuilder setPropertyMethodBuilder = typeBuilder.DefineMethod("set_" + name, MethodAttributes.Public, null, new Type[] { propertyType });

            generator = setPropertyMethodBuilder.GetILGenerator();

            Label returnLabel = generator.DefineLabel();

            // Data members require a getter and setter. However, if the real property is read-only, make sure
            // our surrogate property setter is a no-op.
            if (!pd.IsReadOnly)
            {
                // NOTE: We don't ever set null values, because a property may be required. For
                //       original objects however it's possible that required properties are not
                //       roundtripped, as they may not have RoundtripOriginalAttribute.
                // set {
                //     if (value != null) {
                //         $property.SetValue(_$wrapper, value);
                //     }
                // }

                // If the value is null, return.
                if (!propertyType.IsValueType)
                {
                    generator.Emit(OpCodes.Ldarg_1);
                    EmitBranchIfNull(generator, propertyType, returnLabel);
                }
                else if (TypeUtility.IsNullableType(propertyType))
                {
                    generator.Emit(OpCodes.Ldarga_S, 1);
                    EmitBranchIfNull(generator, propertyType, returnLabel);
                }

                // Get the PropertyDescriptor.
                generator.Emit(OpCodes.Ldsfld, propertyDescFieldBuilder);

                // Push the wrapper object onto the stack. We'll use it as an argument for our
                // call to SetValue later on.
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, wrapperField);

                // Push the value onto the stack. We'll use it as the 2nd argument for
                // our call to SetValue.
                generator.Emit(OpCodes.Ldarg_1);

                // Deal with client-server type conversions.
                if (propertyType != pd.PropertyType)
                {
                    EmitToServerConversion(generator, propertyType, pd.PropertyType);
                }

                // Box value types.
                DynamicMethodUtility.EmitToObjectConversion(generator, pd.PropertyType);

                // PropertyDescriptor.SetValue(_$wrapper, value).
                generator.Emit(OpCodes.Callvirt, typeof(PropertyDescriptor).GetMethod("SetValue"));
            }

            generator.MarkLabel(returnLabel);
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setPropertyMethodBuilder);
        }