Ejemplo n.º 1
0
        /// <summary>
        /// Take a complex object, and transfer properties requested into a dictionary
        /// </summary>
        /// <param name="source"></param>
        /// <param name="context"></param>
        /// <param name="includes"></param>
        /// <param name="visited"></param>
        /// <returns></returns>
        protected Dictionary <string, object> ExpandBlindObject(object source, ContextType context, IEnumerable <PropertyReference> includes, HashSet <int> visited)
        {
            visited = UniqueVisit(source, visited);

            Type sourceType = source.GetType();

            includes = ValidateIncludes(includes, sourceType);

            // Attempt to create a projection object we'll map the data into
            var destinationObject = new Dictionary <string, object>();

            MappingDefinition mappingDefinition = null;

            // Allow any actions to run ahead of mapping
            if (Mappings.ContainsKey(sourceType))
            {
                foreach (var action in Mappings[sourceType]._BeforeExpansion)
                {
                    action(destinationObject, source, context);
                }

                mappingDefinition = Mappings[source.GetType()];
            }

            // Iterate over only the requested properties
            foreach (var propertyReference in includes)
            {
                string propertyName = propertyReference.PropertyName;

                if (mappingDefinition != null)
                {
                    var preparers = mappingDefinition.PrepareProperties;

                    // See if there's a propertyPreparer
                    if (preparers.ContainsKey(propertyName))
                    {
                        preparers[propertyName](destinationObject, null, source, context);
                    }
                }

                // Transform the input value as needed
                object valueToAssign = GetSourceValue(source, context, propertyName, mappingDefinition?.Translators);

                /// If authorization indicates this should not in fact be authorized, skip it
                if (!AuthorizeValue(source, context, valueToAssign))
                {
                    continue;
                }

                if (WillExpand(valueToAssign))
                {
                    valueToAssign = Expand(valueToAssign, context, propertyReference.Children, visited);
                }

                destinationObject[propertyName] = valueToAssign;
            }

            // Allow any actions to run after the mapping
            /// @Todo should this be in reverse order so we have a nested stack style FILO?
            if (Mappings.ContainsKey(sourceType))
            {
                foreach (var action in Mappings[sourceType]._AfterExpansion)
                {
                    action(destinationObject, source, context);
                }
            }

            return(destinationObject);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Verify that we have the appropriate include list for a type, taking into account any requested,
        /// or otherwise defaults supplied.
        /// </summary>
        /// <param name="includes"></param>
        /// <param name="sourceType"></param>
        /// <param name="destType"></param>
        /// <returns></returns>
        private IEnumerable <PropertyReference> ConstructIncludes(IEnumerable <PropertyReference> includes, Type sourceType, Type destType)
        {
            // Out of the gate we want to first see if the only property to be included is a wildcard
            if ((includes.Count() == 1) && (includes.Any(i => i.PropertyName == "*")))
            {
                var wildCardIncludes = new List <PropertyReference> {
                };
                var mapDef           = new MappingDefinition();

                // Check to see if the object is to be blind expanded and make the destination the same as the source if it is
                if (destType == null)
                {
                    destType = sourceType;
                }
                else // in the case that the object isn't to be blind expanded get the proper mapping
                {
                    Mappings.TryGetValue(sourceType, out mapDef);
                }

                // Have all of the destination type properties set to be included
                foreach (PropertyInfo info in destType.GetTypeInfo().GetProperties())
                {
                    var matchingSourceProp = sourceType.GetTypeInfo().GetProperty(info.Name);

                    // Make sure that the property isn't marked as InternalOnly on the sourceType
                    // Which is only an issue if they marked the type to throw an error if it's requested
                    if (matchingSourceProp != null)
                    {
                        if (matchingSourceProp.GetCustomAttributes().Any(att => att.GetType() == typeof(InternalOnlyAttribute)))
                        {
                            // Only add the property if it isn't marked InternalOnly
                            continue;
                        }
                    }

                    // Also make sure that the property exists on the destination type in some capacity
                    // This will never be hit by a blindly expanded object as the source and destination type are identical
                    if (matchingSourceProp == null)
                    {
                        try
                        {
                            // Check to see if there are any translators that would apply the object to the projection ultimately
                            var transTest = mapDef.DefaultDestination().Translators[info.Name];
                        }
                        catch (Exception)
                        {
                            // This property isn't known to the projection at all and thus should not be included
                            continue;
                        }
                    }

                    wildCardIncludes.Add(new PropertyReference {
                        PropertyName = info.Name
                    });
                }

                return(wildCardIncludes);
            }

            if (includes.Any())
            {
                return(includes);
            }

            if (destType == null)
            {
                // in the case of a blind object, default to source properties.  This is a bit dangerous!
                includes = sourceType.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                           .Select(p => new PropertyReference()
                {
                    PropertyName = p.Name
                });
            }

            // if this doesn't have any includes specified, use the default
            if (!includes.Any())
            {
                includes = PropertyReference.Parse(Mappings[sourceType].DestinationForType(destType).DefaultIncludes);
            }

            // if this STILL doesn't have any includes, that means include everything
            if (!includes.Any())
            {
                includes = destType.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                           .Select(p => new PropertyReference()
                {
                    PropertyName = p.Name
                });
            }

            return(includes);
        }