public async Task Get(string[] contentTypeIds, string parent)
        {
            var contentTypes = contentTypeIds.Select(t => ContentTypeProvider.Get(t)).ToList().AsReadOnly();

            if (contentTypes.Count > 1)
            {
                throw new NotImplementedException("Multi type queries are not yet implemented");
            }

            var items = new List <object>();
            var itemChildrenCounts = new Dictionary <string, int>();

            var documentsQuery = ContentFinder.Find(contentTypes.Single().Type);

            if (parent != null)
            {
                documentsQuery.WhereParent(parent);
            }
            else
            {
                documentsQuery.WhereHasNoParent();
            }

            var documents = (await documentsQuery.GetResultAsync().ConfigureAwait(false)).ToList();

            foreach (var content in documents)
            {
                items.Add(content);

                if (content is IHierarchical)
                {
                    var id = PrimaryKeyGetter.Get(content);

                    itemChildrenCounts[string.Join(",", id)] = await ContentChildrenCounter.CountChildrenForAsync(id).ConfigureAwait(false);
                }
            }

            //var sortByPropertyName = typeof(INameable).IsAssignableFrom(contentType.Type) ? "Name" : "Id";
            //var sortByProperty = PropertyDefinitionProvider.GetFor(contentType.Id).FirstOrDefault(p => p.Name == sortByPropertyName);

            //if (sortByProperty != null)
            //{
            //    result = result.OrderBy(i => sortByProperty.Getter(i)).ToList();
            //}

            Response.ContentType = "application/json";

            await Response.WriteAsync(JsonConvert.SerializeObject(new ContentListResult {
                Items = items, ItemChildrenCounts = itemChildrenCounts
            }, new JsonSerializerSettings {
                Formatting = Formatting.Indented, ContractResolver = new CamelCasePropertyNamesContractResolver(), Converters = new List <JsonConverter> {
                    PolymorphicFormConverter
                }
            }));
        }
        public object Route(object root, IEnumerable <string> segments, IEnumerable <ContentTypeDescriptor> types)
        {
            if (!segments.Any())
            {
                if (((IRoutable)root).UrlSegment == null && (!types.Any() || types.Any(t => t.Type == root.GetType())))
                {
                    return(root);
                }

                return(null);
            }

            if (((IRoutable)root).UrlSegment != null && ((IRoutable)root).UrlSegment.Equals(segments.First()))
            {
                segments = segments.Skip(1);
            }

            object content = root;

            while (segments.Any())
            {
                content = ContentSegmentRouter.RouteContentSegment(PrimaryKeyGetter.Get(content), segments.First(), types);

                if (content == null)
                {
                    return(null);
                }

                if (types.Any() && !types.Any(t => t.Type == root.GetType()))
                {
                    return(null);
                }

                segments = segments.Skip(1);
            }

            return(content);
        }
        public async Task <ContentResponseMessage> SaveContent([FromBody] SaveContentRequestBody data)
        {
            if (!ModelState.IsValid)
            {
                return(ContentResponseMessage.CreateFrom(ModelState));
            }

            var contentType = ContentTypeProvider.Get(data.ContentTypeId);

            var b = JsonConvert.DeserializeObject(data.Content, contentType.Type, PolymorphicFormConverter);

            if (!TryValidateModel(b))
            {
                return(ContentResponseMessage.CreateFrom(ModelState));
            }

            if (PrimaryKeyGetter.Get(b).All(id => id != null))
            {
                var a = await ContentGetter.GetAsync(contentType.Id, PrimaryKeyConverter.Convert(data.KeyValues, contentType.Id)).ConfigureAwait(false);

                foreach (var coreInterface in ContentTypeCoreInterfaceProvider.GetFor(contentType.Id))
                {
                    foreach (var propertyDefinition in coreInterface.PropertyDefinitions)
                    {
                        var display = propertyDefinition.Attributes.OfType <DisplayAttribute>().FirstOrDefault();

                        if (display != null && display.GetAutoGenerateField() == false)
                        {
                            continue;
                        }

                        propertyDefinition.Setter(a, propertyDefinition.Getter(b));
                    }
                }

                foreach (var propertyDefinition in PropertyDefinitionProvider.GetFor(contentType.Id))
                {
                    var display = propertyDefinition.Attributes.OfType <DisplayAttribute>().FirstOrDefault();

                    if (display != null && display.GetAutoGenerateField() == false)
                    {
                        continue;
                    }

                    propertyDefinition.Setter(a, propertyDefinition.Getter(b));
                }

                if (!TryValidateModel(b))
                {
                    throw new Exception("a was valid but b was not.");
                }

                await ContentUpdater.UpdateAsync(a).ConfigureAwait(false);

                return(new ContentResponseMessage(true, "Updated"));
            }
            else
            {
                await ContentCreator.CreateAsync(b).ConfigureAwait(false);

                return(new ContentResponseMessage(true, "Created"));
            }
        }