Ejemplo n.º 1
0
        public void BinarySupport()
        {
            Assert.IsFalse(BinaryTypeUtility.IsTypeBinary(typeof(int)),
                           "Int32 isn't a Binary.");
            Assert.IsFalse(BinaryTypeUtility.IsTypeBinary(typeof(string)),
                           "String isn't a Binary.");
            Assert.IsTrue(BinaryTypeUtility.IsTypeBinary(typeof(Binary)),
                          "Binary is a Binary!");

            Assert.AreEqual(typeof(byte[]), SerializationUtility.GetClientType(typeof(Binary)),
                            "The client type for Binary is byte[].");

            byte[] bytes  = new byte[] { 10, 20, 30 };
            Binary binary = new Binary(bytes);

            Assert.IsTrue(bytes.SequenceEqual((IEnumerable <byte>)SerializationUtility.GetClientValue(typeof(byte[]), binary)),
                          "Client Binary values should be equal.");
            Assert.IsTrue(bytes.SequenceEqual((IEnumerable <byte>)SerializationUtility.GetClientValue(typeof(byte[]), bytes)),
                          "Client byte[] values should be equal.");
            Assert.AreEqual(binary, SerializationUtility.GetServerValue(typeof(Binary), binary),
                            "Server Binary values should be equal.");
            Assert.AreEqual(binary, SerializationUtility.GetServerValue(typeof(Binary), bytes),
                            "Server byte[] values should be equal.");
        }
Ejemplo n.º 2
0
        private static OperationDescription CreateOperationDescription(ContractDescription declaringContract, DomainOperationEntry operation)
        {
            OperationDescription operationDesc = ServiceUtility.CreateBasicOperationDescription(declaringContract, operation.Name);

            // Propagate behaviors.
            foreach (IOperationBehavior behavior in operation.Attributes.OfType <IOperationBehavior>())
            {
                operationDesc.Behaviors.Add(behavior);
            }

            // Add standard behaviors.

            if ((operation.Operation == DomainOperation.Query && ((QueryAttribute)operation.OperationAttribute).HasSideEffects) ||
                (operation.Operation == DomainOperation.Invoke && ((InvokeAttribute)operation.OperationAttribute).HasSideEffects))
            {
                // REVIEW: We should actually be able to remove the following line entirely, since
                //         all operations are [WebInvoke] by default.
                ServiceUtility.EnsureBehavior <WebInvokeAttribute>(operationDesc);
            }
            else if (operation.Operation == DomainOperation.Query && !((QueryAttribute)operation.OperationAttribute).HasSideEffects)
            {
                // This is a query with HasSideEffects == false, allow both POST and GET
                var invoke = ServiceUtility.EnsureBehavior <WebInvokeAttribute>(operationDesc);
                invoke.Method = "*";
                // We need to set URI template in order to allow the normal parameters to be extracted from the Uri
                if (operation.Parameters.Count > 0)
                {
                    invoke.UriTemplate = GetDefaultQueryUriTemplate(operation);
                }
            }
            else
            {
                ServiceUtility.EnsureBehavior <WebGetAttribute>(operationDesc);
            }

            string action = ServiceUtility.GetMessageAction(declaringContract, operationDesc.Name, /* action */ null);

            // Define operation input.
            MessageDescription inputMessageDesc = new MessageDescription(action, MessageDirection.Input);

            inputMessageDesc.Body.WrapperName      = operationDesc.Name;
            inputMessageDesc.Body.WrapperNamespace = ServiceUtility.DefaultNamespace;

            for (int i = 0; i < operation.Parameters.Count; i++)
            {
                DomainOperationParameter parameter = operation.Parameters[i];

                MessagePartDescription parameterPartDesc = new MessagePartDescription(parameter.Name, ServiceUtility.DefaultNamespace)
                {
                    Index = i,
                    Type  = SerializationUtility.GetClientType(parameter.ParameterType)
                };
                inputMessageDesc.Body.Parts.Add(parameterPartDesc);
            }
            operationDesc.Messages.Add(inputMessageDesc);

            // Define operation output.
            string responseAction = ServiceUtility.GetResponseMessageAction(declaringContract, operationDesc.Name, /* action */ null);

            MessageDescription outputMessageDesc = new MessageDescription(responseAction, MessageDirection.Output);

            outputMessageDesc.Body.WrapperName      = operationDesc.Name + "Response";
            outputMessageDesc.Body.WrapperNamespace = ServiceUtility.DefaultNamespace;

            if (operation.ReturnType != typeof(void))
            {
                outputMessageDesc.Body.ReturnValue = new MessagePartDescription(operationDesc.Name + "Result", ServiceUtility.DefaultNamespace)
                {
                    Type = SerializationUtility.GetClientType(operation.ReturnType)
                };
            }
            operationDesc.Messages.Add(outputMessageDesc);

            return(operationDesc);
        }
        // Emit a surrogate property for a CLR property.
        // The surrogate code we'll generate will look like this:
        // public <PropertyType> <PropertyName> {
        //     get {
        //         // For normal types.
        //         return _$wrapper.<PropertyName>;
        //
        //         // For Binary.
        //         Binary value = _$wrapper.<PropertyName>;
        //         if (value == null) {
        //             return null;
        //         }
        //         return value.ToArray();
        //     }
        //     set {
        //         if (value == null) {
        //             return;
        //         }
        //
        //         // For normal types.
        //         _$wrapper.<PropertyName> = value;
        //
        //         // For Binary.
        //         Binary valueToStore;
        //         if (value == null) {
        //             valueToStore = null;
        //         }
        //         else {
        //             valueToStore = new Binary(value);
        //         }
        //         _$wrapper.<PropertyName> = valueToStore;
        //     }
        // }
        private static void EmitClrProperty(TypeBuilder typeBuilder, FieldInfo wrapperField, PropertyDescriptor pd, PropertyInfo pi, string name)
        {
            Type            propertyType    = SerializationUtility.GetClientType(pi.PropertyType);
            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.None, propertyType, null);

            CustomAttributeBuilder dataMemberAtt = DataContractSurrogateGenerator.GetDataMemberAttributeBuilder(
                pd.Attributes.OfType <DataMemberAttribute>().FirstOrDefault());

            propertyBuilder.SetCustomAttribute(dataMemberAtt);

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

            // Push the wrapper object onto the stack.
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, wrapperField);
            generator.Emit(OpCodes.Castclass, pi.DeclaringType);

            // Call the property getter.
            generator.Emit(OpCodes.Callvirt, pi.GetGetMethod());

            // Deal with client-server type conversions.
            if (propertyType != pi.PropertyType)
            {
                EmitToClientConversion(generator, pi.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.
            MethodInfo setMethod = pi.GetSetMethod();

            if (setMethod != null && setMethod.IsPublic)
            {
                // 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) {
                //         _$wrapper.Property = 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);
                }

                // Push the wrapper object onto the stack.
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, wrapperField);
                generator.Emit(OpCodes.Castclass, pi.DeclaringType);

                // Push the value onto the stack.
                generator.Emit(OpCodes.Ldarg_1);

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

                // Call the property setter.
                generator.Emit(OpCodes.Callvirt, setMethod);
            }

            generator.MarkLabel(returnLabel);
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setPropertyMethodBuilder);
        }
        // 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);
        }
Ejemplo n.º 5
0
 protected override object ConvertReturnValue(object returnValue)
 {
     return(SerializationUtility.GetClientValue(SerializationUtility.GetClientType(this.operation.ReturnType), returnValue));
 }