public AssociationMetadata(PropertyDescriptor pd)
        {
            this.PropertyDescriptor = pd;
            AttributeCollection propertyAttributes = pd.ExplicitAttributes();

            this.AssociationAttribute = (AssociationAttribute)propertyAttributes[typeof(AssociationAttribute)];
            this.IsExternal           = propertyAttributes[typeof(ExternalReferenceAttribute)] != null;
            this.IsCollection         = EntityGenerator.IsCollectionType(pd.PropertyType);

            if (!this.IsCollection)
            {
                this.PropTypeName        = CodeGenUtilities.GetTypeName(pd.PropertyType);
                this.AssociationTypeName = @"OpenRiaServices.DomainServices.Client.EntityRef<" + this.PropTypeName + ">";
                this.Attributes          = propertyAttributes.Cast <Attribute>().Where(a => a.GetType() != typeof(DataMemberAttribute));
            }
            else
            {
                this.PropTypeName        = CodeGenUtilities.GetTypeName(TypeUtility.GetElementType(pd.PropertyType));
                this.AssociationTypeName = "OpenRiaServices.DomainServices.Client.EntityCollection<" + this.PropTypeName + ">";

                List <Attribute>  attributeList = propertyAttributes.Cast <Attribute>().ToList();
                ReadOnlyAttribute readOnlyAttr  = propertyAttributes.OfType <ReadOnlyAttribute>().SingleOrDefault();
                if (readOnlyAttr != null && !propertyAttributes.OfType <EditableAttribute>().Any())
                {
                    attributeList.Add(new EditableAttribute(!readOnlyAttr.IsReadOnly));
                }
                this.Attributes = attributeList.Where(a => a.GetType() != typeof(DataMemberAttribute));
            }

            this.PropertyName = CodeGenUtilities.GetSafeName(pd.Name);
            this.FieldName    = CodeGenUtilities.MakeCompliantFieldName(this.PropertyName);
        }
示例#2
0
        internal IEnumerable <Attribute> GetPropertyAttributes(PropertyDescriptor propertyDescriptor, Type propertyType)
        {
            List <Attribute> propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast <Attribute>().ToList();

            if (!propertyAttributes.OfType <DataMemberAttribute>().Any())
            {
                propertyAttributes.Add(new DataMemberAttribute());
            }

            ReadOnlyAttribute readOnlyAttr = propertyAttributes.OfType <ReadOnlyAttribute>().SingleOrDefault();

            if (readOnlyAttr != null && !propertyAttributes.OfType <EditableAttribute>().Any())
            {
                propertyAttributes.Add(new EditableAttribute(!readOnlyAttr.IsReadOnly));
            }

            if (TypeUtility.IsSupportedComplexType(propertyType) && !propertyAttributes.OfType <DisplayAttribute>().Any())
            {
                DisplayAttribute displayAttribute = new DisplayAttribute()
                {
                    AutoGenerateField = false
                };
                propertyAttributes.Add(displayAttribute);
            }

            // If the data contract type already contains the RoundtripOriginalAttribute, then we remove the attribute from properties.
            if (this.Type.Attributes()[typeof(RoundtripOriginalAttribute)] != null)
            {
                propertyAttributes.RemoveAll(attr => attr.GetType() == typeof(RoundtripOriginalAttribute));
            }

            return(propertyAttributes);
        }
示例#3
0
        internal override bool CanGenerateProperty(PropertyDescriptor propertyDescriptor)
        {
            // Check if it is an excluded property
            if (propertyDescriptor.Attributes[typeof(ExcludeAttribute)] != null)
            {
                return(false);
            }

            // Check if it is an external reference.
            if (propertyDescriptor.Attributes[typeof(ExternalReferenceAttribute)] != null)
            {
                return(true);
            }

            // The base can't generate the property, it could be an association which we know how to generate.
            if (!base.CanGenerateProperty(propertyDescriptor))
            {
                AttributeCollection propertyAttributes = propertyDescriptor.ExplicitAttributes();
                bool hasKeyAttr = (propertyAttributes[typeof(KeyAttribute)] != null);

                // If we can't generate Key property, log a VS error (this will cancel CodeGen effectively)
                if (hasKeyAttr)
                {
                    // Property must not be serializable based on attributes (e.g. no DataMember), because
                    // we already checked its type which was fine.
                    this.ClientCodeGenerator.CodeGenerationHost.LogError(string.Format(
                                                                             CultureInfo.CurrentCulture,
                                                                             Resource.EntityCodeGen_EntityKey_PropertyNotSerializable,
                                                                             this.Type, propertyDescriptor.Name));

                    return(false);
                }

                // Get the implied element type (e.g. int32[], Nullable<int32>, IEnumerable<int32>)
                // If the ultimate element type is not allowed, it's not acceptable, no matter whether
                // this is an array, Nullable<T> or whatever
                Type elementType = TypeUtility.GetElementType(propertyDescriptor.PropertyType);
                if (!this._domainServiceDescriptionAggregate.EntityTypes.Contains(elementType) || (propertyDescriptor.Attributes[typeof(AssociationAttribute)] == null))
                {
                    // If the base class says we can't generate the property, it is because the property is not serializable.
                    // The only other type entity would serialize is associations. Since it is not, return now.
                    return(false);
                }
            }

            // Ensure the property is not virtual, abstract or new
            // If there is a violation, we log the error and keep
            // running to accumulate all such errors.  This function
            // may return an "okay" for non-error case polymorphics.
            if (!this.CanGeneratePropertyIfPolymorphic(propertyDescriptor))
            {
                return(false);
            }

            return(true);
        }
示例#4
0
        internal override bool HandleNonSerializableProperty(PropertyDescriptor propertyDescriptor)
        {
            AttributeCollection  propertyAttributes = propertyDescriptor.ExplicitAttributes();
            AssociationAttribute associationAttr    = (AssociationAttribute)propertyAttributes[typeof(AssociationAttribute)];
            bool externalReference = propertyAttributes[typeof(ExternalReferenceAttribute)] != null;

            if (associationAttr != null)
            {
                this.AddAssociationToGenerate(propertyDescriptor);
                return(true);
            }

            return(false);
        }
示例#5
0
        internal override bool IsPropertyShared(PropertyDescriptor pd)
        {
            if (base.IsPropertyShared(pd))
            {
                if (pd.ExplicitAttributes()[typeof(KeyAttribute)] != null)
                {
                    // If there are any shared key members, don't generate GetIdentity method.
                    // Default implementation of GetIdentity on the Entity class will be used.
                    this.GenerateGetIdentity = false;
                }
                return(true);
            }

            return(false);
        }
示例#6
0
        internal override void OnPropertySkipped(PropertyDescriptor pd)
        {
            AttributeCollection propertyAttributes = pd.ExplicitAttributes();
            bool hasKeyAttr = (propertyAttributes[typeof(KeyAttribute)] != null);

            // If we can't generate Key property, log a VS error (this will cancel CodeGen effectively)
            if (hasKeyAttr)
            {
                // Property must not be serializable based on attributes (e.g. no DataMember), because
                // we already checked its type which was fine.
                this.ClientCodeGenerator.CodeGenerationHost.LogError(string.Format(
                                                                         CultureInfo.CurrentCulture,
                                                                         Resource.EntityCodeGen_EntityKey_PropertyNotSerializable,
                                                                         this.Type, pd.Name));
            }
        }
        /// <summary>
        /// Returns true if the property should be declared.
        /// </summary>
        /// <remarks>Properties are typically not declared if they are available
        /// through other means (such as shared files) or otherwise excluded from
        /// this type.</remarks>
        /// <param name="pd">The property being declared.</param>
        /// <returns>True if the property should be declared.</returns>
        protected virtual bool ShouldDeclareProperty(PropertyDescriptor pd)
        {
            AttributeCollection propertyAttributes = pd.ExplicitAttributes();

            if (this.IsExcluded(pd, propertyAttributes))
            {
                // Ignore the [Include] because that's what we do during serialization as well. (We don't want to
                // check for [Exclude] + [Include] everywhere in our code base.)
                return(false);
            }

            if (this.IsPropertyShared(pd))
            {
                return(false);
            }

            return(true);
        }
示例#8
0
        internal override bool ShouldDeclareProperty(PropertyDescriptor pd)
        {
            if (!base.ShouldDeclareProperty(pd))
            {
                return(false);
            }

            // Inheritance: when dealing with derived entities, we need to
            // avoid generating a property already on the base.  But we also
            // need to account for flattening (holes in the exposed hiearchy.
            // This helper method encapsulates that logic.
            if (!this.ShouldFlattenProperty(pd))
            {
                return(false);
            }

            AttributeCollection propertyAttributes = pd.ExplicitAttributes();
            Type propertyType = pd.PropertyType;

            // The [Key] attribute means this property is part of entity key
            bool hasKeyAttr = (propertyAttributes[typeof(KeyAttribute)] != null);

            if (hasKeyAttr)
            {
                if (!TypeUtility.IsPredefinedSimpleType(propertyType))
                {
                    this.ClientCodeGenerator.CodeGenerationHost.LogError(string.Format(
                                                                             CultureInfo.CurrentCulture,
                                                                             Resource.EntityCodeGen_EntityKey_KeyTypeNotSupported,
                                                                             this.Type, pd.Name, propertyType));
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Generates a property getter/setter pair into the given proxy class to match the given property info.
        /// </summary>
        /// <param name="propertyDescriptor">PropertyDescriptor for the property to generate for.</param>
        protected virtual void GenerateProperty(PropertyDescriptor propertyDescriptor)
        {
            string propertyName = propertyDescriptor.Name;
            Type   propertyType = CodeGenUtilities.TranslateType(propertyDescriptor.PropertyType);

            // ----------------------------------------------------------------
            // Property type ref
            // ----------------------------------------------------------------
            var propTypeReference = CodeGenUtilities.GetTypeReference(propertyType, this.ClientProxyGenerator, this.ProxyClass);

            // ----------------------------------------------------------------
            // Property decl
            // ----------------------------------------------------------------
            var property = new CodeMemberProperty();

            property.Name       = propertyName;
            property.Type       = propTypeReference;
            property.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed, else becomes virtual
            List <Attribute> propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast <Attribute>().ToList();

            // Generate <summary> for property
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Property_Summary_Comment, propertyName);

            property.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // [DataMember] -> Add if not already present.
            // ----------------------------------------------------------------
            // Add if not already present.

            if (!propertyAttributes.OfType <DataMemberAttribute>().Any())
            {
                CodeAttributeDeclaration dataMemberAtt = CodeGenUtilities.CreateAttributeDeclaration(typeof(DataMemberAttribute), this.ClientProxyGenerator, this.ProxyClass);
                property.CustomAttributes.Add(dataMemberAtt);
            }

            // Here, we check for the existence of [ReadOnly(true)] attributes generated when
            // the property does not not have a setter.  We want to inject an [Editable(false)]
            // attribute into the pipeline.
            ReadOnlyAttribute readOnlyAttr = propertyAttributes.OfType <ReadOnlyAttribute>().SingleOrDefault();

            if (readOnlyAttr != null && !propertyAttributes.OfType <EditableAttribute>().Any())
            {
                propertyAttributes.Add(new EditableAttribute(!readOnlyAttr.IsReadOnly));

                // REVIEW:  should we strip out [ReadOnly] attributes here?
            }

            // Here we check if the type has a RoundtripOriginalAttribute. In that case we strip it out from the property
            if (this._isRoundtripType)
            {
                propertyAttributes.RemoveAll(attr => attr.GetType() == typeof(RoundtripOriginalAttribute));
            }

            // Here we check for database generated fields. In that case we strip any RequiredAttribute from the property.
            if (propertyAttributes.Any(a => a.GetType().Name == "DatabaseGeneratedAttribute"))
            {
                propertyAttributes.RemoveAll(attr => attr.GetType() == typeof(RequiredAttribute));
            }

            // Here, we check for the presence of a complex type. If it exists we need to add a DisplayAttribute
            // if not already there. DataSources windows do not handle complex types
            if (TypeUtility.IsSupportedComplexType(propertyType) && !propertyAttributes.OfType <DisplayAttribute>().Any())
            {
                CodeAttributeDeclaration displayAttribute = CodeGenUtilities.CreateDisplayAttributeDeclaration(this.ClientProxyGenerator, this.ProxyClass);
                property.CustomAttributes.Add(displayAttribute);
            }

            // ----------------------------------------------------------------
            // Propagate the custom attributes
            // ----------------------------------------------------------------

            CustomAttributeGenerator.GenerateCustomAttributes(
                this.ClientProxyGenerator,
                this.ProxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, property.Name, this.ProxyClass.Name, ex.InnerException.Message),
                propertyAttributes.Cast <Attribute>(),
                property.CustomAttributes,
                property.Comments);

            // ----------------------------------------------------------------
            // backing private field (CodeDom doesn't yet know about auto properties)
            // ----------------------------------------------------------------
            string fieldName = CodeGenUtilities.MakeCompliantFieldName(propertyName);
            var    field     = new CodeMemberField(propTypeReference, fieldName);

            this.ProxyClass.Members.Add(field);
            var fieldRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName);
            var valueRef = new CodePropertySetValueReferenceExpression();

            // ----------------------------------------------------------------
            // getter body
            // ----------------------------------------------------------------
            property.GetStatements.Add(new CodeMethodReturnStatement(fieldRef));

            // ----------------------------------------------------------------
            // setter body
            // ----------------------------------------------------------------
            List <CodeStatement> bodyStatements = new List <CodeStatement>();

            // this.OnPropertyXxxChanging(PropType value);
            bodyStatements.Add(this.NotificationMethodGen.GetMethodInvokeExpressionStatementFor(propertyName + "Changing"));

            bool propertyIsReadOnly = this.IsPropertyReadOnly(propertyDescriptor);

            if (!propertyIsReadOnly)
            {
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaiseDataMemberChanging", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }

            // Generate the validation tests.
            CodeStatement validationCode = GeneratePropertySetterValidation(propertyDescriptor.Name);

            bodyStatements.Add(validationCode);

            // this._field = value
            bodyStatements.Add(new CodeAssignStatement(fieldRef, valueRef));

            if (!propertyIsReadOnly)
            {
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaiseDataMemberChanged", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }
            else
            {
                // even read-only members need to raise PropertyChanged
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaisePropertyChanged", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }

            // this.OnPropertyXxxChanged();
            bodyStatements.Add(this.NotificationMethodGen.GetMethodInvokeExpressionStatementFor(propertyName + "Changed"));

            // if (this._field != value)...
            CodeExpression valueTest = CodeGenUtilities.MakeNotEqual(propertyType, fieldRef, valueRef, this.ClientProxyGenerator.IsCSharp);

            CodeConditionStatement body = new CodeConditionStatement(valueTest, bodyStatements.ToArray <CodeStatement>());

            property.SetStatements.Add(body);

            // add property
            this.ProxyClass.Members.Add(property);
        }
示例#10
0
        public TypePropertyMetadata(PropertyDescriptor descriptor)
        {
            _propertyDescriptor = descriptor;
            ValidationRules     = new List <TypePropertyValidationRuleMetadata>();


            var elementType = TypeUtility.GetElementType(descriptor.PropertyType);


            IsArray = !(elementType == descriptor.PropertyType);


            var propertyAttributes = descriptor.ExplicitAttributes();


            IsKey = null != propertyAttributes[typeof(KeyAttribute)];


            // TODO, 336102, ReadOnlyAttribute for editability?  RIA used EditableAttribute?
            IsReadOnly = propertyAttributes.OfType <ReadOnlyAttribute>().Any(a => a.IsReadOnly);


            var associationAttr = propertyAttributes.OfType <AssociationAttribute>().SingleOrDefault();

            if (associationAttr != null)
            {
                Association = new TypePropertyAssociationMetadata(associationAttr);
            }


            var requiredAttribute = propertyAttributes.OfType <RequiredAttribute>().SingleOrDefault();

            if (requiredAttribute != null)
            {
                ValidationRules.Add(new TypePropertyValidationRuleMetadata(requiredAttribute));
            }

            #region Validation Rules

            var rangeAttribute = (RangeAttribute)propertyAttributes[typeof(RangeAttribute)];
            if (rangeAttribute != null)
            {
                var operandType = rangeAttribute.OperandType;
                operandType = Nullable.GetUnderlyingType(operandType) ?? operandType;
                if (operandType == typeof(Double) ||
                    operandType == typeof(Int16) ||
                    operandType == typeof(Int32) ||
                    operandType == typeof(Int64) ||
                    operandType == typeof(Single))
                {
                    ValidationRules.Add(new TypePropertyValidationRuleMetadata(rangeAttribute));
                }
            }


            var stringLengthAttribute = (StringLengthAttribute)propertyAttributes[typeof(StringLengthAttribute)];
            if (stringLengthAttribute != null)
            {
                ValidationRules.Add(new TypePropertyValidationRuleMetadata(stringLengthAttribute));
            }


            var dataTypeAttribute = (DataTypeAttribute)propertyAttributes[typeof(DataTypeAttribute)];
            if (dataTypeAttribute != null)
            {
                if (dataTypeAttribute.DataType.Equals(DataType.EmailAddress) ||
                    dataTypeAttribute.DataType.Equals(DataType.Url))
                {
                    ValidationRules.Add(new TypePropertyValidationRuleMetadata(dataTypeAttribute));
                }
            }

            #endregion
        }