示例#1
0
        /// <summary>
        /// Serialize the root object for a request.
        /// This should always be BroadsoftDocument
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        private XElement SerializeRoot <T>(BroadsoftDocument <T> document) where T : OCICommand
        {
            var documentType = typeof(BroadsoftDocument <T>);

            var ns = XNamespace.None;

            // By default, element name will by the class name
            var elementName = "BroadsoftDocument";

            // XmlRoot attribute will contain useful information such as namespace
            var xmlRootAttr = AttributeUtil.Get <XmlRootAttribute>(documentType);

            if (xmlRootAttr != null)
            {
                // Override defaults if attribute properties are set
                if (xmlRootAttr.Namespace != null)
                {
                    ns = xmlRootAttr.Namespace;
                }

                if (!string.IsNullOrEmpty(xmlRootAttr.ElementName))
                {
                    elementName = xmlRootAttr.ElementName;
                }
            }

            // Element contents is an object contianing all attributes and elements under this element
            return(new XElement(ns + elementName,
                                new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
                                new XAttribute(XNamespace.Xmlns + "xsd", "http://www.w3.org/2001/XMLSchema"),
                                GetElementContentsForInstance(documentType, document)));
        }
        /// <summary>
        /// Retrieves all the properties/groups that are part of the group
        /// </summary>
        /// <param name="options"></param>
        /// <param name="instanceType"></param>
        /// <returns></returns>
        private IEnumerable <string> OptionNames(IEnumerable <ChoiceOption> options, Type instanceType)
        {
            return(options.Select(opt =>
            {
                if (opt is ChoiceFieldOption fieldOpt)
                {
                    return fieldOpt.Name;
                }
                else if (opt is ChoiceSequenceOption sequenceOpt)
                {
                    var seqProperties =
                        instanceType.GetProperties()
                        .Where(prop => AttributeUtil.Get <XmlIgnoreAttribute>(prop) == null)
                        .Where(prop =>
                    {
                        var groupAttribute = AttributeUtil.Get <GroupAttribute>(prop);

                        return groupAttribute != null && groupAttribute.Id == sequenceOpt.Sequence.Id;
                    })
                        .Select(prop => prop.Name);

                    return $"[{string.Join(", ", seqProperties)}]";
                }
                else
                {
                    throw new InvalidOperationException("Unknown choice option");
                }
            }));
        }
        /// <summary>
        /// Determine if a field in sequence has been set
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="instance"></param>
        /// <returns></returns>
        private bool IsSequenceSet(Sequence sequence, object instance)
        {
            var set = false;

            // Get properties that are part of sequence
            var requiredProperties =
                instance.GetType().GetProperties()
                .Where(prop => AttributeUtil.Get <XmlIgnoreAttribute>(prop) == null)
                .Where(prop =>
            {
                var groupAttribute = AttributeUtil.Get <GroupAttribute>(prop);

                return(groupAttribute != null && groupAttribute.Id == sequence.Id);
            });

            foreach (var property in requiredProperties)
            {
                if (IsFieldSet(property, instance))
                {
                    set = true;
                }
            }

            return(set);
        }
        /// <summary>
        /// Validate sequence group
        /// </summary>
        /// <param name="instance"></param>
        /// <returns>A list of all errors encountered.</returns>
        public override IEnumerable <ValidationError> Validate(object instance)
        {
            var errors = new List <ValidationError>();
            var type   = instance.GetType();

            // Get all properties on object that are part of this group and required
            var requiredProperties =
                type.GetProperties()
                .Where(prop => AttributeUtil.Get <OptionalAttribute>(prop) == null)
                .Where(prop => AttributeUtil.Get <XmlIgnoreAttribute>(prop) == null)
                .Where(prop =>
            {
                var groupAttribute = AttributeUtil.Get <GroupAttribute>(prop);

                return(groupAttribute != null && groupAttribute.Id == Id);
            });

            // Check if required properties are set
            foreach (var prop in requiredProperties)
            {
                var set = false;

                if (Validator.IsPropertySpecified(prop, instance))
                {
                    var value             = prop.GetValue(instance, null);
                    var valueAsEnumerable = value as IEnumerable <object>;

                    if (valueAsEnumerable != null)
                    {
                        // Enumerables must have at least one entry
                        set = valueAsEnumerable.Count() > 0;
                    }
                    else
                    {
                        // Other values must not be null
                        set = value != null;
                    }
                }

                if (!set)
                {
                    errors.Add(new FieldNotSetError(instance, prop.Name));
                }
            }

            // Validate any child groups
            if (Children != null)
            {
                foreach (var child in Children)
                {
                    errors.AddRange(child.Validate(instance));
                }
            }

            return(errors);
        }
示例#5
0
        /// <summary>
        /// Serializes an Enum value to a string
        /// </summary>
        /// <param name="enumType"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private string EnumForValue(Type enumType, string value)
        {
            var xmlEnumAttr = AttributeUtil.Get <XmlEnumAttribute>(enumType.GetField(value));

            if (xmlEnumAttr == null)
            {
                throw new ArgumentException("Enum doesn't have XmlEnum attribute", nameof(value));
            }

            return(xmlEnumAttr.Name);
        }
示例#6
0
        public void TestAttributeUtilGet()
        {
            TestClass2 item  = new TestClass2(7, "test", 0);
            object     value = AttributeUtil.Get(() => item.Id, typeof(StringValueAttribute), "Value");

            Assert.IsNotNull(value);
            Assert.IsTrue(((string)value).StartsWith("IdTest"));
            value = AttributeUtil.Get(() => item.Name, typeof(StringValueAttribute), "Value");
            Assert.AreEqual("NameTest", value);
            value = AttributeUtil.Get(() => item.Age, typeof(StringValueAttribute), "Value");
            Assert.IsNull(value);
        }
        /// <summary>
        /// Determines if a value is an object that should be ran through the validator
        /// </summary>
        /// <param name="value"></param>
        /// <returns>If an object should be ran through the Validate method.</returns>
        private static bool IsValidatableObject(object value)
        {
            if (value is object)
            {
                var type = value.GetType();

                return(!type.IsPrimitive &&                                   // Ignore primitives
                       !type.Equals(typeof(string)) &&                        // Ignore strings
                       !type.IsEnum &&                                        // Ignore enums
                       AttributeUtil.Get <XmlIgnoreAttribute>(type) == null); // Ignore anything explicitly marked as ignore
            }
            else
            {
                return(false);
            }
        }
示例#8
0
        /// <summary>
        /// Returns all the child attributes and elements in serialized form for an object
        /// </summary>
        /// <param name="type"></param>
        /// <param name="instance"></param>
        /// <returns></returns>
        private List <XObject> GetElementContentsForInstance(Type type, object instance)
        {
            var contents = new List <XObject>();

            // Get all properties that are marked with XmlElementAttribute or XmlAttributeAttribute
            var properties = type.GetProperties()
                             .Where(prop => AttributeUtil.GetAll(prop).Any(attr => attr is XmlElementAttribute || attr is XmlAttributeAttribute));

            foreach (var property in properties)
            {
                if (IsPropertySpecified(property, type, instance))
                {
                    var elementAttr   = AttributeUtil.Get <XmlElementAttribute>(property);
                    var attributeAttr = AttributeUtil.Get <XmlAttributeAttribute>(property);

                    // Handle property if it's an XML Element
                    if (elementAttr != null)
                    {
                        var propertyValue = property.GetValue(instance);

                        // If property value is a list, create an element for each entry. Else just create an element for the value.
                        var isList = property.PropertyType.GetInterfaces()
                                     .Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IList <>));

                        if (isList)
                        {
                            foreach (var entry in (IEnumerable)propertyValue)
                            {
                                contents.Add(SerializeElement(property, entry, elementAttr));
                            }
                        }
                        else
                        {
                            contents.Add(SerializeElement(property, propertyValue, elementAttr));
                        }
                    }
                    // Handle property if it's an XML Attribute
                    else if (attributeAttr != null)
                    {
                        contents.Add(SerializeAttribute(property, property.GetValue(instance), attributeAttr));
                    }
                }
            }

            return(contents);
        }
        /// <summary>
        /// Determine if the given property was manually set on an object
        /// </summary>
        /// <param name="property"></param>
        /// <param name="instance"></param>
        public static bool IsPropertySpecified(PropertyInfo property, object instance)
        {
            // Skip properties marked as Ignored to serializer
            if (AttributeUtil.Get <XmlIgnoreAttribute>(property) != null)
            {
                return(false);
            }

            var type = instance.GetType();
            var specifiedFieldName = $"{property.Name}Specified";
            var specifiedProperty  = type.GetProperty(specifiedFieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

            if (specifiedProperty == null)
            {
                throw new InvalidOperationException($"{specifiedFieldName} does not exist");
            }

            return((bool)specifiedProperty.GetValue(instance));
        }
示例#10
0
        /// <summary>
        /// Deserialize a string to enum
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <returns></returns>
        private object DeserializeEnum(string value, Type targetType)
        {
            if (!targetType.IsEnum)
            {
                throw new ArgumentException("Type is not an Enum", nameof(targetType));
            }

            var enumValue = targetType.GetFields().Where(field =>
            {
                var enumAttr = AttributeUtil.Get <XmlEnumAttribute>(field);

                return(enumAttr?.Name == value);
            }).FirstOrDefault();

            if (enumValue == null)
            {
                throw new InvalidOperationException($"Value {value} has no corresponding enum value on {targetType}");
            }

            return(Enum.Parse(targetType, enumValue.Name));
        }
        /// <summary>
        /// Retrieve Sequence and Choice groups on an object
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        private static IEnumerable <Group> GetGroups(object instance)
        {
            var groups = new List <Group>();
            var type   = instance.GetType();

            while (type != null)
            {
                // Object should have a Groups attribute containing the group details as JSON
                var groupsAttr = AttributeUtil.Get <GroupsAttribute>(type);

                if (groupsAttr == null)
                {
                    throw new ArgumentException("No Groups attribute on object", nameof(instance));
                }

                if (groupsAttr != null)
                {
                    // Parse JSON
                    using (var ms = new MemoryStream(Encoding.ASCII.GetBytes(groupsAttr.Json)))
                    {
                        groups.AddRange(_serializer.ReadObject(ms) as List <Group>);
                    }
                }

                if ((type.BaseType != null) && (type.BaseType != typeof(Object)))
                {
                    type = type.BaseType;
                }
                else
                {
                    type = null;
                }
            }

            return(groups);
        }
示例#12
0
        /// <summary>
        /// Deserialize an element
        /// </summary>
        /// <param name="element"></param>
        /// <param name="targetType"></param>
        /// <returns></returns>
        private object DeserializeElement(XElement element, Type targetType)
        {
            // Serialize to primitive value if primitive or enum
            if (IsValueType(targetType))
            {
                return(DeserializeValueType(element.Value, targetType));
            }

            // If the target type is abstract, then there should be an attribute on the XML element
            // telling us the concrete type
            if (targetType.IsAbstract)
            {
                var typeAttribute = element.Attribute(xsiNamespace + "type");

                if (typeAttribute != null)
                {
                    targetType = Type.GetType($"{ModelNamespace}.{typeAttribute.Value.Replace("c:", "C.")}");
                }
            }

            if (targetType == null)
            {
                throw new ArgumentException("targetType cannot be null", nameof(targetType));
            }

            var obj = Activator.CreateInstance(targetType);

            // Iterate through properties in the object and set it
            var properties = targetType.GetProperties();

            foreach (var property in properties)
            {
                var propertyType   = property.PropertyType;
                var propertyIsList = propertyType.GetTypeInfo().IsGenericType&& propertyType.GetGenericTypeDefinition() == typeof(List <>);

                var elementAttr   = AttributeUtil.Get <XmlElementAttribute>(property);
                var attributeAttr = AttributeUtil.Get <XmlAttributeAttribute>(property);

                // Handle when property is for an XML element
                if (elementAttr != null)
                {
                    if (propertyIsList)
                    {
                        // Since the destination is a list, we need to get the type the list is composed of so we can construct them.
                        var individualType = propertyType.GetTypeInfo().GenericTypeArguments[0];

                        // Get elements from the XML for the property
                        var childElements = element.Elements(elementAttr.ElementName);

                        if (childElements.Count() > 0)
                        {
                            var list = Activator.CreateInstance(propertyType) as IList;

                            foreach (var childElement in childElements)
                            {
                                list.Add(DeserializeElement(childElement, individualType));
                            }

                            property.SetValue(obj, list);
                        }
                    }
                    else
                    {
                        var childElement = element.Element(elementAttr.ElementName);

                        if (childElement != null)
                        {
                            property.SetValue(obj, DeserializeElement(childElement, propertyType));
                        }
                    }
                }
                // Handle when property is for an XML attribute
                else if (attributeAttr != null)
                {
                    var attribute = element.Attribute(attributeAttr.AttributeName);

                    if (attribute != null)
                    {
                        property.SetValue(obj, attribute.Value);
                    }
                }
            }

            return(obj);
        }
示例#13
0
        /// <summary>
        /// Validate choice group
        /// </summary>
        /// <param name="instance"></param>
        /// <returns>A list of all errors encountered.</returns>
        public override IEnumerable <ValidationError> Validate(object instance)
        {
            var errors = new List <ValidationError>();
            var type   = instance.GetType();

            // Get all properties on object that are part of this group
            var requiredProperties =
                type.GetProperties()
                .Where(prop => AttributeUtil.Get <XmlIgnoreAttribute>(prop) == null)
                .Where(prop =>
            {
                var groupAttribute = AttributeUtil.Get <GroupAttribute>(prop);

                return(groupAttribute != null && groupAttribute.Id == Id);
            });

            var options = new List <ChoiceOption>();

            options.AddRange(requiredProperties.Select(prop => new ChoiceFieldOption()
            {
                Name     = prop.Name,
                Optional = AttributeUtil.Get <OptionalAttribute>(prop) != null,
                Set      = IsFieldSet(prop, instance)
            }));

            if (Children != null)
            {
                // Find any Sequences that are children
                foreach (var child in Children)
                {
                    if (child is Sequence sequence)
                    {
                        var isSet = IsSequenceSet(sequence, instance);

                        // If any of the sequences have set fields, validate the Sequence to
                        // enforce all required fields
                        if (isSet)
                        {
                            errors.AddRange(sequence.Validate(instance));
                        }

                        options.Add(new ChoiceSequenceOption()
                        {
                            Sequence = sequence,
                            Optional = false,
                            Set      = isSet
                        });
                    }
                }
            }

            var setMembers         = options.Where(opt => opt.Set);
            var nonOptionalMembers = options.Where(opt => !opt.Optional);

            if ((setMembers.Count() == 0) && (nonOptionalMembers.Count() != 0) && !Optional)
            {
                errors.Add(new ChoiceNotSetError(instance, OptionNames(options, type)));
            }
            else if (setMembers.Count() > 1)
            {
                errors.Add(new InvalidChoiceError(instance, OptionNames(options, type)));
            }

            return(errors);
        }