public static void ResourceDocument(ParameterExpression jsonWriter, ResourceModel model, Expression resource, Expression options, Action <ParameterExpression> variable, Action <Expression> statement, IMetaModelRepository models) { var uriResolverFunc = MakeMemberAccess(options, SerializationContextUriResolverPropertyInfo); var contextUri = StringConcat( Call(MakeMemberAccess(options, SerializationContextBaseUriPropertyInfo), typeof(object).GetMethod(nameof(ToString))), Constant(".hydra/context.jsonld")); var resolver = Variable(typeof(CustomResolver), "resolver"); variable(resolver); statement(Assign(resolver, New(typeof(CustomResolver)))); foreach (var exp in WriteBeginObjectContext(jsonWriter, contextUri)) { statement(exp); } WriteNode(jsonWriter, model, resource, variable, statement, uriResolverFunc, models, new Stack <ResourceModel>(), resolver); statement(JsonWriterMethods.WriteEndObject(jsonWriter)); }
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()))); }