Func <object, SerializationContext, Stream, Task> GetFuncFromResponseResourceType(object entityInstance)
        {
            if (entityInstance == null)
            {
                return(null);
            }

            return(_models.TryGetResourceModel(entityInstance.GetType(), out var responseEntityResourceModel)
        ? responseEntityResourceModel.Hydra().SerializeFunc
        : null);
        }
        void AnnotateCollectionTypes(IMetaModelRepository repository, ResourceModel model)
        {
            var enumerableTypes = model.ResourceType.EnumerableItemTypes().ToList();

            var enumerableType = enumerableTypes.FirstOrDefault();

            if (enumerableType != null && repository.TryGetResourceModel(enumerableType, out var itemModel))
            {
                var hydraResourceModel = model.Hydra();
                hydraResourceModel.Collection.IsCollection          = true;
                hydraResourceModel.Collection.ItemModel             = itemModel;
                hydraResourceModel.Collection.IsFrameworkCollection =
                    enumerableType == model.ResourceType || (model.ResourceType.IsGenericType &&
                                                             model.ResourceType.GetGenericTypeDefinition() == typeof(List <>));
            }
        }
Exemplo n.º 3
0
        public Task WriteTo(object entity, IHttpEntity response, IEnumerable <string> codecParameters)
        {
            _responseMessage.Headers.Add("link", $"<{_apiDocumentationLink}>; rel=\"{_apiDocumentationRel}\"");

            if (entity == null)
            {
                return(Task.CompletedTask);
            }

            var resourceSelectedByUri = _context.PipelineData.SelectedResource;
            var resourceModel         = resourceSelectedByUri.ResourceModel;

            if (resourceModel.ResourceType.IsInstanceOfType(entity) == false)
            {
                if (!_models.TryGetResourceModel(entity.GetType(), out resourceModel))
                {
                    throw new InvalidOperationException($"Hydra serialiser not found for object of type {entity.GetType()}");
                }
            }

            var currentResourceModelName = resourceModel.Name;
            var serializerFunc           = resourceModel.Hydra().SerializeFunc;

            var typeToTypeGen = _models.ResourceRegistrations
                                .Where(res => res.ResourceType != null && res.Hydra().JsonLdTypeFunc != null)
                                .ToLookup(res => res.ResourceType, res => res.Hydra().JsonLdTypeFunc);

            string renderTypeNode(object resource)
            {
                var convertedString = typeToTypeGen[resource.GetType()].First()(resource);

                if (convertedString.StartsWith("http://") || convertedString.StartsWith("https://") || IsCurie(convertedString))
                {
                    return(convertedString);
                }
                return(BaseUri + convertedString);
            }

            return(serializerFunc(entity, new SerializationContext
            {
                BaseUri = BaseUri,
                UriGenerator = resource => _uris.CreateUri(resource, _context.ApplicationBaseUri, currentResourceModelName),
                TypeGenerator = renderTypeNode
            }, response.Stream));
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var type             = (Type)value;
            var hasResourceModel = _models.TryGetResourceModel(type, out var model);
            var vocab            = model?.Hydra().Vocabulary;

            if (!hasResourceModel || vocab == null)
            {
                writer.WriteValue(type.AssemblyQualifiedName);
                return;
            }

            writer.WriteStartObject();
            writer.WritePropertyName("property");
            writer.WriteValue("rdf:type");
            writer.WritePropertyName("object");
            writer.WriteValue($"{vocab.DefaultPrefix}:{type.Name}");
            writer.WriteEndObject();
        }
        public IDictionary <string, object> Decorate(object entity, IMetaModelRepository _models, Uri baseUri, IDictionary <string, object> dic)
        {
            var type = entity.GetType();

            if (entity is Collection collection)
            {
                dic["Member"] = new List <IDictionary <string, object> >();

                foreach (var member in collection.Member)
                {
                    recursed = true;
                    var data = Decorate(member, _models, baseUri, dic);
                    data = data.Where(x => x.Value != null).ToDictionary(key => MakeCamelCase(key.Key), value => value.Value);
                    ((List <IDictionary <string, object> >)dic["Member"]).Add(data);
                }

                recursed = false;
            }

            //JsonSerializer.SetDefaultResolver(StandardResolver.AllowPrivateExcludeNullCamelCase);

            //CompositeResolver.RegisterAndSetAsDefault(new[] {new Myforammter(),}, new[] {StandardResolver.AllowPrivateExcludeNullCamelCase});


            var jsonProperties = entity.ToProperties();

            //var list = new List<KeyValuePair<string, object>>(jsonProperties);

            var isNode = entity is JsonLd.INode;

            if (_models.TryGetResourceModel(type, out var resourceModel))
            {
                var hydraModel = resourceModel.Hydra();
                TryAddType(type, jsonProperties, hydraModel);
                if (isNode)
                {
                    TryAddId(jsonProperties, entity, baseUri);
                }
            }

            AddContext(jsonProperties, baseUri);

            //UTF8 won't camelCase dictionary keys :(

            //Tried ExpandoObject but same problem

            //dynamic myObj = new ExpandoObject();
            //myObj.@id = "id";
            //((IDictionary<string, object>) myObj)["SpecialAge"] = 123;

            //var x = new Error {Message = "oops"};

            if (entity is Collection hydraCollection)
            {
                jsonProperties["Member"] = dic["Member"];
                var id = jsonProperties["identifier"];
                jsonProperties.Remove("identifier");
                jsonProperties["@id"] = id;
            }


            return(jsonProperties);
        }
Exemplo n.º 6
0
        static void WriteNode(
            ParameterExpression jsonWriter,
            ResourceModel model,
            Expression resource,
            Action <ParameterExpression> var,
            Action <Expression> statement,
            MemberExpression uriResolver,
            IMetaModelRepository models,
            Stack <ResourceModel> recursionDefender,
            ParameterExpression jsonResolver)
        {
            var resourceType = model.ResourceType;

            if (recursionDefender.Contains(model))
            {
                throw new InvalidOperationException(
                          $"Detected recursion, already processing {resourceType?.Name}: {string.Join("->", recursionDefender.Select(m => m.ResourceType?.Name).Where(n => n != null))}");
            }

            recursionDefender.Push(model);

            var type = GetTypeName(models, model);
            var uri  = GetUri(resource, uriResolver);

            var collectionItemTypes = CollectionItemTypes(resourceType).ToList();

            Type collectionItemType;

            if (collectionItemTypes.Count() == 1 &&
                models.TryGetResourceModel((collectionItemType = collectionItemTypes.First()), out _))
            {
                var collectionType =
                    typeof(OpenRasta.Plugins.Hydra.Schemas.Hydra.Hydra.Collection <>).MakeGenericType(collectionItemType);
                var collection = Variable(collectionType);
                var(collection);
                statement(Assign(collection,
                                 New(collectionType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(collectionItemType) }),
                                     resource)));
                resource     = collection;
                type         = "hydra:Collection"; // hack, lazy, 2am.
                resourceType = collectionType;
            }

            foreach (var exp in model.Uris.Any()
        ? WriteIdType(jsonWriter, type, uri, model)
        : WriteType(jsonWriter, type))
            {
                statement(exp);
            }


            foreach (var pi in resourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (pi.CustomAttributes.Any(a => a.AttributeType.Name == "JsonIgnoreAttribute"))
                {
                    continue;
                }

                if (pi.GetIndexParameters().Any())
                {
                    continue;
                }

                if (pi.PropertyType.IsValueType && Nullable.GetUnderlyingType(pi.PropertyType) == null)
                {
                    WriteNodePropertyValue(jsonWriter, var, statement, pi, jsonResolver,
                                           MakeMemberAccess(resource, pi));
                    continue;
                }


                WriteNodeProperty(jsonWriter, resource, var, statement, uriResolver, models, recursionDefender, pi,
                                  jsonResolver);
            }

            recursionDefender.Pop();
        }
Exemplo n.º 7
0
        static void WriteNodeProperty(ParameterExpression jsonWriter, Expression resource,
                                      Action <ParameterExpression> variable, Action <Expression> statement,
                                      MemberExpression uriResolverFunc, IMetaModelRepository models, Stack <ResourceModel> recursionDefender,
                                      PropertyInfo pi,
                                      ParameterExpression resolver)
        {
            var propertyStatements = new List <Expression>();
            var propertyVars       = new List <ParameterExpression>();

            // var propertyValue;
            var propertyValue = Variable(pi.PropertyType, $"val{pi.DeclaringType.Name}{pi.Name}");

            variable(propertyValue);

            // propertyValue = resource.Property;
            statement(Assign(propertyValue, MakeMemberAccess(resource, pi)));


            if (models.TryGetResourceModel(pi.PropertyType, out var propertyResourceModel))
            {
                // property has a registration, it's either an iri node or a blank node
                propertyStatements.Add(JsonWriterMethods.WriteValueSeparator(jsonWriter));
                propertyStatements.Add(WritePropertyName(jsonWriter, GetJsonPropertyName(pi)));
                propertyStatements.Add(JsonWriterMethods.WriteBeginObject(jsonWriter));
                WriteNode(jsonWriter, propertyResourceModel, propertyValue, propertyVars.Add, propertyStatements.Add,
                          uriResolverFunc, models, recursionDefender, resolver);
                propertyStatements.Add(JsonWriterMethods.WriteEndObject(jsonWriter));
            }
            else
            {
                // not an iri node itself, but is it a list of nodes?
                var itemResourceRegistrations = (
                    from i in pi.PropertyType.GetInterfaces()
                    where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)
                    let itemType = i.GetGenericArguments()[0]
                                   where itemType != typeof(object)
                                   let resourceModels = models.ResourceRegistrations.Where(r => itemType.IsAssignableFrom(r.ResourceType))
                                                        where resourceModels.Any()
                                                        orderby resourceModels.Count() descending
                                                        select new
                {
                    itemType, models =
                        (from possible in resourceModels
                         orderby possible.ResourceType.GetInheritanceDistance(itemType)
                         select possible).ToList()
                }).FirstOrDefault();

                if (itemResourceRegistrations == null)
                {
                    // not a list of iri or blank nodes
                    WriteNodePropertyValue(jsonWriter, propertyVars.Add, propertyStatements.Add, pi, resolver,
                                           MakeMemberAccess(resource, pi));
                }
                else
                {
                    // it's a list of nodes
                    var itemArrayType = itemResourceRegistrations.itemType.MakeArrayType();
                    var itemArray     = Variable(itemArrayType);

                    var toArrayMethod = typeof(Enumerable).GetMethod("ToArray")
                                        .MakeGenericMethod(itemResourceRegistrations.itemType);
                    var assign = Assign(itemArray, Call(toArrayMethod, propertyValue));
                    propertyVars.Add(itemArray);
                    propertyStatements.Add(assign);

                    var i = Variable(typeof(int));
                    propertyVars.Add(i);

                    var initialValue = Assign(i, Constant(0));
                    propertyStatements.Add(initialValue);

                    var itemVars       = new List <ParameterExpression>();
                    var itemStatements = new List <Expression>();

                    var @break = Label("break");

                    propertyStatements.Add(JsonWriterMethods.WriteValueSeparator(jsonWriter));
                    propertyStatements.Add(WritePropertyName(jsonWriter, GetJsonPropertyName(pi)));

                    propertyStatements.Add(JsonWriterMethods.WriteBeginArray(jsonWriter));

                    itemStatements.Add(IfThen(GreaterThan(i, Constant(0)), JsonWriterMethods.WriteValueSeparator(jsonWriter)));
                    itemStatements.Add(JsonWriterMethods.WriteBeginObject(jsonWriter));

                    BlockExpression resourceBlock(ResourceModel r, ParameterExpression typed)
                    {
                        var vars       = new List <ParameterExpression>();
                        var statements = new List <Expression>();

                        WriteNode(
                            jsonWriter,
                            r,
                            typed,
                            vars.Add, statements.Add,
                            uriResolverFunc, models, recursionDefender, resolver);
                        return(Block(vars.ToArray(), statements.ToArray()));
                    }

                    Expression renderBlock = Block(Throw(New(typeof(InvalidOperationException))));

                    // with C : B : A, if is C else if is B else if is A else throw

                    foreach (var specificModel in itemResourceRegistrations.models)
                    {
                        var typed = Variable(specificModel.ResourceType, "as" + specificModel.ResourceType.Name);
                        itemVars.Add(typed);
                        var @as = Assign(typed, TypeAs(ArrayAccess(itemArray, i), specificModel.ResourceType));
                        renderBlock = IfThenElse(
                            NotEqual(@as, Default(specificModel.ResourceType)),
                            resourceBlock(specificModel, @typed),
                            renderBlock);
                    }

                    itemStatements.Add(renderBlock);
                    itemStatements.Add(PostIncrementAssign(i));
                    itemStatements.Add(JsonWriterMethods.WriteEndObject(jsonWriter));
                    var loop = Loop(
                        IfThenElse(
                            LessThan(i, MakeMemberAccess(itemArray, itemArrayType.GetProperty("Length"))),
                            Block(itemVars.ToArray(), itemStatements.ToArray()),
                            Break(@break)),
                        @break
                        );
                    propertyStatements.Add(loop);
                    propertyStatements.Add(JsonWriterMethods.WriteEndArray(jsonWriter));
                }
            }

            statement(IfThen(
                          NotEqual(propertyValue, Default(pi.PropertyType)),
                          Block(propertyVars.ToArray(), propertyStatements.ToArray())));
        }
Exemplo n.º 8
0
        static CodeBlock WriteNode(
            Variable <JsonWriter> jsonWriter,
            TypedExpression <string> baseUri,
            ResourceModel model,
            Expression resource,
            MemberAccess <Func <object, string> > uriGenerator,
            MemberAccess <Func <object, string> > typeGenerator,
            IMetaModelRepository models,
            Variable <HydraJsonFormatterResolver> jsonFormatterResolver,
            NodeProperty[] existingNodeProperties   = null,
            Stack <ResourceModel> recursionDefender = null)
        {
            recursionDefender = recursionDefender ?? new Stack <ResourceModel>();
            var resourceType = model.ResourceType;

            if (recursionDefender.Contains(model))
            {
                throw new InvalidOperationException(
                          $"Detected recursion, already processing {resourceType?.Name}: {string.Join("->", recursionDefender.Select(m => m.ResourceType?.Name).Where(n => n != null))}");
            }

            recursionDefender.Push(model);

            var resourceRegistrationHydraType = HydraTextExtensions.GetHydraTypeName(model);
            var resourceUri = uriGenerator.Invoke(resource);

            List <NodeProperty> nodeProperties =
                new List <NodeProperty>(existingNodeProperties ?? Enumerable.Empty <NodeProperty>());

            nodeProperties.AddRange(GetNodeProperties(
                                        jsonWriter,
                                        baseUri,
                                        model,
                                        resource,
                                        uriGenerator,
                                        typeGenerator,
                                        models,
                                        recursionDefender,
                                        jsonFormatterResolver,
                                        resourceType,
                                        resourceUri,
                                        resourceRegistrationHydraType));


            var  collectionItemTypes = HydraTextExtensions.CollectionItemTypes(resourceType).ToList();
            Type collectionItemType  = null;
            var  isHydraCollection   = collectionItemTypes.Count == 1 &&
                                       models.TryGetResourceModel(collectionItemType = collectionItemTypes.First(), out _);

            IEnumerable <AnyExpression> render()
            {
                if (isHydraCollection)
                {
                    var collectionType = HydraTypes.Collection.MakeGenericType(collectionItemType);
                    var collectionCtor =
                        collectionType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(collectionItemType) });
                    var collection = Expression.Variable(collectionType);

                    yield return(collection);

                    var instantiateCollection = Expression.Assign(collection, Expression.New(collectionCtor, resource));
                    yield return(instantiateCollection);

                    resource = collection;

                    // if we have a generic list of sort, we hydra:Collection instead
                    if (resourceType.IsGenericType) // IEnum<T>, List<T> etc
                    {
                        resourceRegistrationHydraType = "hydra:Collection";
                    }

                    resourceType = collectionType;

                    // Remove existing id and type if already defined
                    nodeProperties.RemoveAll(p => p.Name == "@id" || p.Name == "@type");
                    nodeProperties.AddRange(GetNodeProperties(jsonWriter, baseUri, model, resource, uriGenerator, typeGenerator,
                                                              models,
                                                              recursionDefender,
                                                              jsonFormatterResolver, resourceType, resourceUri, resourceRegistrationHydraType));
                }

                if (nodeProperties.Any())
                {
                    yield return(WriteNodeProperties(jsonWriter, nodeProperties));
                }
            }

            recursionDefender.Pop();
            return(new CodeBlock(render()));
        }
Exemplo n.º 9
0
        static NodeProperty WriteNodeProperty(
            Variable <JsonWriter> jsonWriter,
            TypedExpression <string> baseUri,
            Expression resource,
            MemberAccess <Func <object, string> > uriGenerator,
            MemberAccess <Func <object, string> > typeGenerator,
            IMetaModelRepository models,
            Stack <ResourceModel> recursionDefender,
            PropertyInfo pi,
            Variable <HydraJsonFormatterResolver> jsonFormatterResolver)
        {
            // var propertyValue;
            var propertyValue = Expression.Variable(pi.PropertyType, $"val{pi.DeclaringType.Name}{pi.Name}");

            // propertyValue = resource.Property;
            var propertyValueAssignment = Expression.Assign(propertyValue, Expression.MakeMemberAccess(resource, pi));

            var preamble = new InlineCode(new Expression[] { propertyValue, propertyValueAssignment });

            if (models.TryGetResourceModel(pi.PropertyType, out var propertyResourceModel))
            {
                var jsonPropertyName = HydraTextExtensions.GetJsonPropertyName(pi);
                return(new NodeProperty(jsonPropertyName)
                {
                    Preamble = preamble,
                    Code = new InlineCode(new[]
                    {
                        jsonWriter.WritePropertyName(jsonPropertyName),
                        jsonWriter.WriteBeginObject(),
                        WriteNode(jsonWriter, baseUri, propertyResourceModel, propertyValue,
                                  uriGenerator, typeGenerator, models, jsonFormatterResolver, recursionDefender: recursionDefender),
                        jsonWriter.WriteEndObject()
                    }),
                    Conditional = Expression.NotEqual(propertyValue, Expression.Default(pi.PropertyType))
                });
            }

            var itemTypes = (from i in pi.PropertyType.GetInterfaces()
                             .Concat(pi.PropertyType.IsInterface ? new[] { pi.PropertyType } : Array.Empty <Type>())
                             where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)
                             let itemType = i.GetGenericArguments()[0]
                                            where itemType != typeof(object)
                                            select itemType).ToList();

            // not an iri node itself, but is it a list of nodes?
            var itemResourceRegistrations = (
                from itemType in itemTypes
                let resourceModels = models.ResourceRegistrations.Where(r =>
                                                                        r.ResourceType != null && itemType.IsAssignableFrom(r.ResourceType)).ToList()
                                     where resourceModels.Any()
                                     orderby resourceModels.Count() descending
                                     select
                                     (
                    itemType,
                    (from possible in resourceModels
                     orderby possible.ResourceType.GetInheritanceDistance(itemType)
                     select possible).ToList()
                                     )).ToList <(Type itemType, List <ResourceModel> models)>();

            if (itemResourceRegistrations.Any() == false)
            {
                // not a list of iri or blank nodes
                var propValue = WriteNodePropertyValue(jsonWriter, pi, jsonFormatterResolver, resource);
                propValue.Preamble    = preamble;
                propValue.Conditional = Expression.NotEqual(propertyValue, Expression.Default(pi.PropertyType));
                return(propValue);
            }

            // it's a list of nodes
            return(WriteNodeList(jsonWriter, baseUri, uriGenerator, typeGenerator, models, recursionDefender, pi,
                                 jsonFormatterResolver,
                                 itemResourceRegistrations, propertyValue, preamble));
        }