Skip to content

Commit

Permalink
Add virtual method to extend the complex property serialization (#656)
Browse files Browse the repository at this point in the history
* Add virtual method to extend the complex property serialization

* Update the public API test cases

* Fix the typo
  • Loading branch information
xuzhg authored Aug 12, 2022
1 parent f1db770 commit a59ad11
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -749,16 +749,16 @@ private async Task WriteDynamicComplexPropertiesAsync(ResourceContext resourceCo
if (edmTypeReference.IsStructured() ||
(edmTypeReference.IsCollection() && edmTypeReference.AsCollection().ElementType().IsStructured()))
{
ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo
{
IsCollection = edmTypeReference.IsCollection(),
Name = dynamicComplexProperty.Key,
};
ODataNestedResourceInfo nestedResourceInfo
= CreateDynamicComplexNestedResourceInfo(dynamicComplexProperty.Key, dynamicComplexProperty.Value, edmTypeReference, resourceContext);

await writer.WriteStartAsync(nestedResourceInfo).ConfigureAwait(false);
await WriteDynamicComplexPropertyAsync(dynamicComplexProperty.Value, edmTypeReference, resourceContext, writer)
.ConfigureAwait(false);
await writer.WriteEndAsync().ConfigureAwait(false);
if (nestedResourceInfo != null)
{
await writer.WriteStartAsync(nestedResourceInfo).ConfigureAwait(false);
await WriteDynamicComplexPropertyAsync(dynamicComplexProperty.Value, edmTypeReference, resourceContext, writer)
.ConfigureAwait(false);
await writer.WriteEndAsync().ConfigureAwait(false);
}
}
}
}
Expand Down Expand Up @@ -834,16 +834,14 @@ private async Task WriteComplexPropertiesAsync(SelectExpandNode selectExpandNode
{
IEdmStructuralProperty complexProperty = selectedComplex.Key;

ODataNestedResourceInfo nestedResourceInfo = new ODataNestedResourceInfo
ODataNestedResourceInfo nestedResourceInfo = CreateComplexNestedResourceInfo(complexProperty, selectedComplex.Value, resourceContext);
if (nestedResourceInfo != null)
{
IsCollection = complexProperty.Type.IsCollection(),
Name = complexProperty.Name
};

await writer.WriteStartAsync(nestedResourceInfo).ConfigureAwait(false);
await WriteComplexAndExpandedNavigationPropertyAsync(complexProperty, selectedComplex.Value, resourceContext, writer)
.ConfigureAwait(false);
await writer.WriteEndAsync().ConfigureAwait(false);
await writer.WriteStartAsync(nestedResourceInfo).ConfigureAwait(false);
await WriteComplexAndExpandedNavigationPropertyAsync(complexProperty, selectedComplex.Value, resourceContext, writer)
.ConfigureAwait(false);
await writer.WriteEndAsync().ConfigureAwait(false);
}
}
}

Expand Down Expand Up @@ -960,6 +958,59 @@ private IEnumerable<ODataNestedResourceInfo> CreateNavigationLinks(
}
}

/// <summary>
/// Creates the <see cref="ODataNestedResourceInfo"/> to be written while writing this dynamic complex property.
/// </summary>
/// <param name="propertyName">The dynamic property name.</param>
/// <param name="propertyValue">The dynamic property value.</param>
/// <param name="edmType">The edm type reference.</param>
/// <param name="resourceContext">The context for the complex instance being written.</param>
/// <returns>The nested resource info to be written. Returns 'null' will omit this serialization.</returns>
/// <remarks>It enables customer to get more control by overriding this method. </remarks>
public virtual ODataNestedResourceInfo CreateDynamicComplexNestedResourceInfo(string propertyName, object propertyValue, IEdmTypeReference edmType, ResourceContext resourceContext)
{
ODataNestedResourceInfo nestedInfo = null;
if (propertyName != null && edmType != null)
{
nestedInfo = new ODataNestedResourceInfo
{
IsCollection = edmType.IsCollection(),
Name = propertyName,
};
}

return nestedInfo;
}

/// <summary>
/// Creates the <see cref="ODataNestedResourceInfo"/> to be written while writing this complex property.
/// </summary>
/// <param name="complexProperty">The complex property for which the nested resource info is being created.</param>
/// <param name="pathSelectItem">The corresponding sub select item belongs to this complex property.</param>
/// <param name="resourceContext">The context for the complex instance being written.</param>
/// <returns>The nested resource info to be written. Returns 'null' will omit this complex serialization.</returns>
/// <remarks>It enables customer to get more control by overriding this method. </remarks>
public virtual ODataNestedResourceInfo CreateComplexNestedResourceInfo(IEdmStructuralProperty complexProperty, PathSelectItem pathSelectItem, ResourceContext resourceContext)
{
if (complexProperty == null)
{
throw Error.ArgumentNull(nameof(complexProperty));
}

ODataNestedResourceInfo nestedInfo = null;

if (complexProperty.Type != null)
{
nestedInfo = new ODataNestedResourceInfo
{
IsCollection = complexProperty.Type.IsCollection(),
Name = complexProperty.Name
};
}

return nestedInfo;
}

/// <summary>
/// Creates the <see cref="ODataNestedResourceInfo"/> to be written while writing this entity.
/// </summary>
Expand Down
51 changes: 35 additions & 16 deletions src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,20 @@
<param name="clrType">The type to test.</param>
<returns>True if the type is a DateTime; false otherwise.</returns>
</member>
<member name="M:Microsoft.AspNetCore.OData.Common.TypeHelper.IsDateOnly(System.Type)">
<summary>
Determine if a type is a <see cref="T:System.DateOnly"/>.
</summary>
<param name="clrType">The type to test.</param>
<returns>True if the type is a DateOnly; false otherwise.</returns>
</member>
<member name="M:Microsoft.AspNetCore.OData.Common.TypeHelper.IsTimeOnly(System.Type)">
<summary>
Determine if a type is a <see cref="T:System.TimeOnly"/>.
</summary>
<param name="clrType">The type to test.</param>
<returns>True if the type is a TimeOnly; false otherwise.</returns>
</member>
<member name="M:Microsoft.AspNetCore.OData.Common.TypeHelper.IsTimeSpan(System.Type)">
<summary>
Determine if a type is a TimeSpan.
Expand Down Expand Up @@ -4606,6 +4620,27 @@
Write the navigation link for the select navigation properties.
</summary>
</member>
<member name="M:Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateDynamicComplexNestedResourceInfo(System.String,System.Object,Microsoft.OData.Edm.IEdmTypeReference,Microsoft.AspNetCore.OData.Formatter.ResourceContext)">
<summary>
Creates the <see cref="T:Microsoft.OData.ODataNestedResourceInfo"/> to be written while writing this dynamic complex property.
</summary>
<param name="propertyName">The dynamic property name.</param>
<param name="propertyValue">The dynamic property value.</param>
<param name="edmType">The edm type reference.</param>
<param name="resourceContext">The context for the complex instance being written.</param>
<returns>The nested resource info to be written. Returns 'null' will omit this serialization.</returns>
<remarks>It enables customer to get more controll by overriding this method. </remarks>
</member>
<member name="M:Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateComplexNestedResourceInfo(Microsoft.OData.Edm.IEdmStructuralProperty,Microsoft.OData.UriParser.PathSelectItem,Microsoft.AspNetCore.OData.Formatter.ResourceContext)">
<summary>
Creates the <see cref="T:Microsoft.OData.ODataNestedResourceInfo"/> to be written while writing this complex property.
</summary>
<param name="complexProperty">The complex property for which the nested resource info is being created.</param>
<param name="pathSelectItem">The corresponding sub select item belongs to this complex property.</param>
<param name="resourceContext">The context for the complex instance being written.</param>
<returns>The nested resource info to be written. Returns 'null' will omit this complex serialization.</returns>
<remarks>It enables customer to get more controll by overriding this method. </remarks>
</member>
<member name="M:Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateNavigationLink(Microsoft.OData.Edm.IEdmNavigationProperty,Microsoft.AspNetCore.OData.Formatter.ResourceContext)">
<summary>
Creates the <see cref="T:Microsoft.OData.ODataNestedResourceInfo"/> to be written while writing this entity.
Expand Down Expand Up @@ -14382,19 +14417,3 @@
</member>
</members>
</doc>
ummary>
<param name="segment">The value segment.</param>
</member>
<member name="P:Microsoft.AspNetCore.OData.Routing.Template.ValueSegmentTemplate.Segment">
<summary>
Gets the value segment.
</summary>
</member>
<member name="M:Microsoft.AspNetCore.OData.Routing.Template.ValueSegmentTemplate.GetTemplates(Microsoft.AspNetCore.OData.Routing.ODataRouteOptions)">
<inheritdoc />
</member>
<member name="M:Microsoft.AspNetCore.OData.Routing.Template.ValueSegmentTemplate.TryTranslate(Microsoft.AspNetCore.OData.Routing.Template.ODataTemplateTranslateContext)">
<inheritdoc />
</member>
</members>
</doc>
2 changes: 2 additions & 0 deletions src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,9 @@ virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataEdmTypeSerialize
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataEnumSerializer.CreateODataEnumValue(object graph, Microsoft.OData.Edm.IEdmEnumTypeReference enumType, Microsoft.AspNetCore.OData.Formatter.Serialization.ODataSerializerContext writeContext) -> Microsoft.OData.ODataEnumValue
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataPrimitiveSerializer.CreateODataPrimitiveValue(object graph, Microsoft.OData.Edm.IEdmPrimitiveTypeReference primitiveType, Microsoft.AspNetCore.OData.Formatter.Serialization.ODataSerializerContext writeContext) -> Microsoft.OData.ODataPrimitiveValue
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.AppendDynamicProperties(Microsoft.OData.ODataResource resource, Microsoft.AspNetCore.OData.Formatter.Serialization.SelectExpandNode selectExpandNode, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> void
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateComplexNestedResourceInfo(Microsoft.OData.Edm.IEdmStructuralProperty complexProperty, Microsoft.OData.UriParser.PathSelectItem pathSelectItem, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> Microsoft.OData.ODataNestedResourceInfo
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateComputedProperty(string propertyName, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> Microsoft.OData.ODataProperty
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateDynamicComplexNestedResourceInfo(string propertyName, object propertyValue, Microsoft.OData.Edm.IEdmTypeReference edmType, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> Microsoft.OData.ODataNestedResourceInfo
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateETag(Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> string
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateNavigationLink(Microsoft.OData.Edm.IEdmNavigationProperty navigationProperty, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> Microsoft.OData.ODataNestedResourceInfo
virtual Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSerializer.CreateODataAction(Microsoft.OData.Edm.IEdmAction action, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext) -> Microsoft.OData.ODataAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,34 @@ public async Task WriteObjectInlineAsync_WritesODataResourceFrom_CreateResource(
writer.Verify();
}

[Fact]
public async Task WriteObjectInlineAsync_Calls_CreateComplexNestedResourceInfo_ForEachSelectedComplexProperty()
{
// Arrange
SelectExpandNode selectExpandNode = new SelectExpandNode
{
SelectedComplexProperties = new Dictionary<IEdmStructuralProperty, PathSelectItem>
{
{ new Mock<IEdmStructuralProperty>().Object, null },
{ new Mock<IEdmStructuralProperty>().Object, null }
}
};

Mock<ODataWriter> writer = new Mock<ODataWriter>();
Mock<ODataResourceSerializer> serializer = new Mock<ODataResourceSerializer>(_serializerProvider);
serializer.Setup(s => s.CreateSelectExpandNode(It.IsAny<ResourceContext>())).Returns(selectExpandNode);
serializer.CallBase = true;

serializer.Setup(s => s.CreateComplexNestedResourceInfo(selectExpandNode.SelectedComplexProperties.ElementAt(0).Key, null, It.IsAny<ResourceContext>())).Verifiable();
serializer.Setup(s => s.CreateComplexNestedResourceInfo(selectExpandNode.SelectedComplexProperties.ElementAt(1).Key, null, It.IsAny<ResourceContext>())).Verifiable();

// Act
await serializer.Object.WriteObjectInlineAsync(_customer, _customerType, writer.Object, _writeContext);

// Assert
serializer.Verify();
}

[Fact]
public async Task WriteObjectInlineAsync_Calls_CreateNavigationLink_ForEachSelectedNavigationProperty()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,9 @@ public class Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSer
public ODataResourceSerializer (Microsoft.AspNetCore.OData.Formatter.Serialization.IODataSerializerProvider serializerProvider)

public virtual void AppendDynamicProperties (Microsoft.OData.ODataResource resource, Microsoft.AspNetCore.OData.Formatter.Serialization.SelectExpandNode selectExpandNode, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateComplexNestedResourceInfo (Microsoft.OData.Edm.IEdmStructuralProperty complexProperty, Microsoft.OData.UriParser.PathSelectItem pathSelectItem, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataProperty CreateComputedProperty (string propertyName, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateDynamicComplexNestedResourceInfo (string propertyName, object propertyValue, Microsoft.OData.Edm.IEdmTypeReference edmType, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual string CreateETag (Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateNavigationLink (Microsoft.OData.Edm.IEdmNavigationProperty navigationProperty, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataAction CreateODataAction (Microsoft.OData.Edm.IEdmAction action, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,9 @@ public class Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSer
public ODataResourceSerializer (Microsoft.AspNetCore.OData.Formatter.Serialization.IODataSerializerProvider serializerProvider)

public virtual void AppendDynamicProperties (Microsoft.OData.ODataResource resource, Microsoft.AspNetCore.OData.Formatter.Serialization.SelectExpandNode selectExpandNode, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateComplexNestedResourceInfo (Microsoft.OData.Edm.IEdmStructuralProperty complexProperty, Microsoft.OData.UriParser.PathSelectItem pathSelectItem, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataProperty CreateComputedProperty (string propertyName, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateDynamicComplexNestedResourceInfo (string propertyName, object propertyValue, Microsoft.OData.Edm.IEdmTypeReference edmType, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual string CreateETag (Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateNavigationLink (Microsoft.OData.Edm.IEdmNavigationProperty navigationProperty, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataAction CreateODataAction (Microsoft.OData.Edm.IEdmAction action, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,9 @@ public class Microsoft.AspNetCore.OData.Formatter.Serialization.ODataResourceSer
public ODataResourceSerializer (Microsoft.AspNetCore.OData.Formatter.Serialization.IODataSerializerProvider serializerProvider)

public virtual void AppendDynamicProperties (Microsoft.OData.ODataResource resource, Microsoft.AspNetCore.OData.Formatter.Serialization.SelectExpandNode selectExpandNode, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateComplexNestedResourceInfo (Microsoft.OData.Edm.IEdmStructuralProperty complexProperty, Microsoft.OData.UriParser.PathSelectItem pathSelectItem, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataProperty CreateComputedProperty (string propertyName, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateDynamicComplexNestedResourceInfo (string propertyName, object propertyValue, Microsoft.OData.Edm.IEdmTypeReference edmType, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual string CreateETag (Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataNestedResourceInfo CreateNavigationLink (Microsoft.OData.Edm.IEdmNavigationProperty navigationProperty, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
public virtual Microsoft.OData.ODataAction CreateODataAction (Microsoft.OData.Edm.IEdmAction action, Microsoft.AspNetCore.OData.Formatter.ResourceContext resourceContext)
Expand Down

0 comments on commit a59ad11

Please sign in to comment.