Skip to content

Commit

Permalink
fixes #931: Undeclared enum type value for untype value serialized as…
Browse files Browse the repository at this point in the history
… empty resource (#961)

* fixes #931: Undeclared enum type value for untype value serialized as empty resource

* Update the comments.
  • Loading branch information
xuzhg committed Aug 10, 2023
1 parent 1d63aba commit f83634d
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ public virtual void AppendDynamicProperties(ODataResource resource, SelectExpand

IEdmStructuredType structuredType = resourceContext.StructuredType;
IEdmStructuredObject structuredObject = resourceContext.EdmObject;
ODataSerializerContext serializierContext = resourceContext.SerializerContext;
object value;
IDelta delta = structuredObject as IDelta;
if (structuredObject is EdmUntypedObject untypedObject) // NO CLR, NO EDM
Expand Down Expand Up @@ -700,10 +701,25 @@ public virtual void AppendDynamicProperties(ODataResource resource, SelectExpand
continue;
}

IEdmTypeReference edmTypeReference = resourceContext.SerializerContext.GetEdmType(dynamicPropertyValue,
dynamicPropertyValue.GetType(), true);
Type propertyType = dynamicPropertyValue.GetType();
IEdmTypeReference edmTypeReference = serializierContext.GetEdmType(dynamicPropertyValue, propertyType, true);
if (edmTypeReference == null || edmTypeReference.IsStructuredOrUntyped())
{
if (TypeHelper.IsEnum(propertyType))
{
// we don't have the Edm enum type in the model, let's write it as string.
dynamicProperties.Add(new ODataProperty
{
Name = dynamicProperty.Key,

// TBD: Shall we write the un-declared enum value as full-name string?
// So, "Data":"Apple" => should be ""Data":"Namespace.EnumTypeName.Apple" ?
Value = dynamicPropertyValue.ToString()
});

continue;
}

resourceContext.AppendDynamicOrUntypedProperty(dynamicProperty.Key, dynamicPropertyValue);
}
else
Expand All @@ -716,7 +732,7 @@ public virtual void AppendDynamicProperties(ODataResource resource, SelectExpand
}

dynamicProperties.Add(propertySerializer.CreateProperty(
dynamicPropertyValue, edmTypeReference, dynamicProperty.Key, resourceContext.SerializerContext));
dynamicPropertyValue, edmTypeReference, dynamicProperty.Key, serializierContext));
}
}

Expand Down Expand Up @@ -1388,8 +1404,23 @@ public virtual object CreateUntypedPropertyValue(IEdmStructuralProperty structur
// 1) If we can get EdmType from model, Let's use it.
// 2) If no (aka, we don't have an Edm type associated). So, let's treat it a Untyped.
actualType = writeContext.GetEdmType(propertyValue, propertyType, true);

if (actualType.IsStructuredOrUntyped())
{
if (TypeHelper.IsEnum(propertyType))
{
// we don't have the Edm enum type in the model, let's write it as string.
return new ODataProperty
{
Name = structuralProperty.Name,

// Shall we write the un-declared enum value as full-name string?
// So, "Data":"Apple" => should be ""Data":"Namespace.EnumTypeName.Apple" ?
// We keep it simple to write it as string (enum member name), not the full-name string.
Value = propertyValue.ToString()
};
}

return propertyValue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ public static IList<InModelPerson> GetAllPeople()
}
},

// not in model enum
new InModelPerson
{
Id = 22, // special Id number
Name = "Yin",
Data = NotInModelEnum.Apple,
Infos = new object[] { InModelColor.Blue, InModelColor.Green, NotInModelEnum.Apple },
Containers = new Dictionary<string, object>
{
{ "EnumDynamic1", InModelColor.Blue },
{ "EnumDynamic2", NotInModelEnum.Apple },
}
},

// In model complex
new InModelPerson
{
Expand Down
28 changes: 28 additions & 0 deletions test/Microsoft.AspNetCore.OData.E2E.Tests/Untyped/UntypedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,34 @@ public async Task QuerySinglePeople_OnDeclaredUntypedProperty(string request, st
Assert.Equal(expected, payloadBody);
}

[Fact]
public async Task QuerySinglePeople_WithDeclaredOrUndeclaredEnum_OnUntypedAndDynamicProperty()
{
// Arrange
HttpClient client = CreateClient();

// Act
HttpResponseMessage response = await client.GetAsync("odata/people/22");

// Assert
Assert.NotNull(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

string payloadBody = await response.Content.ReadAsStringAsync();

Assert.Equal("{\"@odata.context\":\"http://localhost/odata/$metadata#People/$entity\"," +
"\"Id\":22," +
"\"Name\":\"Yin\"," +
"\"EnumDynamic1@odata.type\":\"#Microsoft.AspNetCore.OData.E2E.Tests.Untyped.InModelColor\"," +
"\"EnumDynamic1\":\"Blue\"," +
"\"EnumDynamic2\":\"Apple\"," +
"\"Data@odata.type\":\"#String\"," +
"\"Data\":\"Apple\"," +
"\"Infos\":[\"Blue\",\"Green\",\"Apple\"]" +
"}", payloadBody);
}

[Fact]
public async Task QuerySinglePeople_WithCollectionInCollection_OnDeclaredUntypedProperty()
{
Expand Down

0 comments on commit f83634d

Please sign in to comment.