New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serialization exception when 2 subtypes define a property with the same name but different types #706

Open
ArnoudRoo opened this Issue Sep 27, 2016 · 11 comments

Comments

Projects
None yet
10 participants
@ArnoudRoo

ArnoudRoo commented Sep 27, 2016

Exception when 2 types inherit from the same BaseType and use the same name for a property but with different property Types.
The error of error 1 gets thrown when requesting the data without filters out of the entity sets E11021 and Entity of Example EntitySets. The property that causes this issue is SourceTable, which is of the type Edm.String on BusinessCubeCalc and Edm.Guid on BusinessCubeFactMeasure.
This same configuration was working in 6.15.0.

Assemblies affected

Microsoft.OData.Core (7.0.0.0)

Reproduce steps

The example model and entity sets can be used. The entity sets Entity and E11021 fail with the error as in Actual Result, the other sets can be queried correctly. Doing a request without filters is all that is needed to let the exception occur.

Example model:





<EntityType Name="BusinessCubeElement" BaseType="VisionWaves.Entity" Abstract="true">
    <Property Name="ParentId" Type="Edm.Guid" Nullable="false" />
    <Property Name="Name" Type="Edm.String" Nullable="false" />
    <Property Name="Description" Type="Edm.String" />
    <Property Name="CubeSourceName" Type="Edm.String" />
    <NavigationProperty Name="Parent" Type="VisionWaves.Entity" />
</EntityType>

<EntityType Name="BusinessCubeCalc" BaseType="VisionWaves.Business.BusinessCubeElement" Abstract="true">
    <Property Name="SourceTable" Type="Edm.String" />
    <Property Name="MdxExpression" Type="Edm.String" Nullable="false" />
</EntityType>


<EntityType Name="BusinessCubeFact" BaseType="VisionWaves.Business.BusinessCubeElement" Abstract="true">
    <Property Name="CubeStorageMode" Type="Edm.Byte" Nullable="false" />
    <Property Name="Partitioning" Type="Edm.Boolean" Nullable="false" />
    <Property Name="PartitioningUnitId" Type="Edm.Guid" Nullable="false" />
    <NavigationProperty Name="DimensionsDisabled" Type="Collection(VisionWaves.Business.BusinessCubeDimension)" />
    <NavigationProperty Name="DimensionsKey" Type="Collection(VisionWaves.Business.BusinessCubeDimension)" />
    <NavigationProperty Name="PartitioningUnit" Type="VisionWaves.Types.TimeUnit" />
</EntityType>


<EntityType Name="BusinessCubeFactMeasure" BaseType="VisionWaves.Business.BusinessCubeFact">
    <Property Name="DisplayFolder" Type="Edm.String" />
    <Property Name="AggregationFunction" Type="Edm.String" Nullable="false" />
    <Property Name="DataType" Type="Edm.String" Nullable="false" />
    <Property Name="Visible" Type="Edm.Boolean" Nullable="false" />
    <Property Name="SourceBindingType" Type="Edm.String" Nullable="false" />
    <Property Name="SourceTable" Type="Edm.Guid" Nullable="false" />
    <Property Name="SourceColumn" Type="Edm.String" />
    <Property Name="SourceDataType" Type="Edm.String" />
    <Property Name="SourceDataSize" Type="Edm.Int16" />
</EntityType>                       

Example EntitySets:

<EntitySet Name="Entity" EntityType="VisionWaves.Entity" />
<EntitySet Name="E11021" EntityType="VisionWaves.Business.BusinessCubeElement" />
<EntitySet Name="E11050" EntityType="VisionWaves.Business.BusinessCubeCalc" />
<EntitySet Name="E11040" EntityType="VisionWaves.Business.BusinessCubeFact" />
<EntitySet Name="E11043" EntityType="VisionWaves.Business.BusinessCubeFactMeasure" />

Expected result

The data of the entity sets.

Actual result

Error 1:
{
"error": {
"code": "",
"message": "An error has occurred.",
"innererror": {
"message": "An incompatible primitive type 'Edm.Guid[Nullable=False]' was found for an item that was expected to be of type 'Edm.String[Nullable=True]'.",
"type": "Microsoft.OData.ODataException",
"stacktrace": " at Microsoft.OData.ValidationUtils.ValidateMetadataPrimitiveType(IEdmTypeReference expectedTypeReference, IEdmTypeReference typeReferenceFromValue)\r\n at Microsoft.OData.WriterValidator.ValidateIsExpectedPrimitiveType(Object value, IEdmPrimitiveTypeReference valuePrimitiveTypeReference, IEdmTypeReference expectedTypeReference)\r\n at Microsoft.OData.JsonLight.ODataJsonLightValueSerializer.WritePrimitiveValue(Object value, IEdmTypeReference actualTypeReference, IEdmTypeReference expectedTypeReference)\r\n at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperties(IEdmStructuredType owningType, IEnumerable`1 properties, Boolean isComplexValue, IDuplicatePropertyNameChecker duplicatePropertyNameChecker)\r\n at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource(ODataResource resource)\r\n at Microsoft.OData.ODataWriterCore.InterceptException(Action action)\r\n at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation(ODataResource resource)\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSerializer.WriteResource(Object graph, ODataWriter writer, ODataSerializerContext writeContext, IEdmTypeReference expectedType)\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext)\r\n at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Owin.HttpMessageHandlerAdapter.d__13.MoveNext()"
}
}
}

Additional details

Optional, details of the root cause if known. Delete this section if you have no additional details to add.

@ArnoudRoo

This comment has been minimized.

ArnoudRoo commented Oct 4, 2016

The WriteProperty method in the ODataJsonLightPropertySerializer invokes the JsonLightOutputContext.PropertyCacheHandler.GetProperty with the propertyName and owning type. In the GetProperty method only the propertyName and the currentResourceScope is taken into account to determine the uniqeName, which is used to check if the item is in the cache, which causes the problem.

I've created an own version which also takes the resource type full name into account, this fixes the problem.

Is it possible to include a similar fix?

@qswinson

This comment has been minimized.

qswinson commented Oct 18, 2016

This issue is a breaking change from OData 6.15 to 7.0 that is preventing my project's upgrade. Is there any way to configure the ODataJsonLightWriter to not validate the data until a fix for this issue can be made?

@ArnoudRoo

This comment has been minimized.

ArnoudRoo commented Oct 19, 2016

Hey Qswinson,

I did make a small change to the code and recompiled it, so it takes the full name into account while accessing the cache. If disabling strong name checking is an option for you, i can send you the code changes.

Regards,
Arnoud

@qswinson

This comment has been minimized.

qswinson commented Oct 19, 2016

Thanks @ArnoudRoo. I need to keep with the official NuGet packaging for my project. Have you submitted a PR with your fix? It might help getting this bug prioritized.

@tyrius02

This comment has been minimized.

tyrius02 commented Nov 16, 2016

I am able to reproduce the same exception with a different model and request. In our case we have a class, Release, with optional navigation properties to both a Family and a Snapshot:

<EntityType Name="Family">
  <Key>
    <PropertyRef Name="Id" />
  </Key>
  <Property Name="Id" Type="Edm.String" Nullable="false" />
</EntityType>

<EntityType Name="Snapshot">
  <Key>
    <PropertyRef Name="Id" />
  </Key>
  <Property Name="Id" Type="Edm.Guid" Nullable="false" />
</EntityType>

<EntityType Name="Release">
  <Key>
    <PropertyRef Name="Id" />
  </Key>
  <Property Name="Id" Type="Edm.String" Nullable="false" />
  <NavigationProperty Name="Snapshot" Type="ODataSandbox.Models.Snapshot" />
  <NavigationProperty Name="Family" Type="ODataSandbox.Models.Family" />
</EntityType>

<EntitySet Name="Families" EntityType="ODataSandbox.Models.Family" />
<EntitySet Name="Snapshots" EntityType="ODataSandbox.Models.Snapshot" />
<EntitySet Name="Releases" EntityType="ODataSandbox.Models.Release">
  <NavigationPropertyBinding Path="Snapshot" Target="Snapshots" />
  <NavigationPropertyBinding Path="Family" Target="Families" />
</EntitySet>

I receive the exception when I issue a request to the Release endpoint and expand both navigation properties: /Releases?$expand=Snapshot,Family.

This prevents me, too, from upgrading to version 7.0.

@apideveloper

This comment has been minimized.

apideveloper commented Dec 6, 2016

I to am running into this issue. The example by tyrius02 is exactly what I'm running into except change out the types from Edm.String and Edm.Guid to Edm.Int32 and Edm.Int64

An incompatible primitive type 'Edm.Int32[Nullable=False]' was found for an item that was expected to be of type 'Edm.Int64[Nullable=True]'

If I change the name of my property it will work as expected. This breaks my API though as people are expecting Id

Note that this is only affected when the two objects are at the same level such as the example.

@only4study

This comment has been minimized.

only4study commented Dec 15, 2016

I also reproduced this issue.
{
"error": {
"code": "",
"message": "An error has occurred.",
"innererror": {
"message": "An incompatible primitive type 'Edm.Decimal[Nullable=False]' was found for an item that was expected to be of type 'Edm.Int32[Nullable=True]'.",
"type": "Microsoft.OData.ODataException",
"stacktrace": "
at Microsoft.OData.ValidationUtils.ValidateMetadataPrimitiveType(IEdmTypeReference expectedTypeReference, IEdmTypeReference typeReferenceFromValue)\r\n
at Microsoft.OData.WriterValidator.ValidateIsExpectedPrimitiveType(Object value, IEdmPrimitiveTypeReference valuePrimitiveTypeReference, IEdmTypeReference expectedTypeReference)\r\n
at Microsoft.OData.JsonLight.ODataJsonLightValueSerializer.WritePrimitiveValue(Object value, IEdmTypeReference actualTypeReference, IEdmTypeReference expectedTypeReference)\r\n
at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperties(IEdmStructuredType owningType, IEnumerable1 properties, Boolean isComplexValue, IDuplicatePropertyNameChecker duplicatePropertyNameChecker)\r\n at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource(ODataResource resource)\r\n at Microsoft.OData.ODataWriterCore.InterceptException(Action action)\r\n at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation(ODataResource resource)\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSerializer.WriteResource(Object graph, ODataWriter writer, ODataSerializerContext writeContext, IEdmTypeReference expectedType)\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSerializer.WriteComplexProperties(IEnumerable1 complexProperties, ResourceContext resourceContext, ODataWriter writer)\r\n
at System.Web.OData.Formatter.Serialization.ODataResourceSerializer.WriteResource(Object graph, ODataWriter writer, ODataSerializerContext writeContext, IEdmTypeReference expectedType)\r\n
at System.Web.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext)\r\n
at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n
at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n
--- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at System.Web.Http.Owin.HttpMessageHandlerAdapter.d__13.MoveNext()"
}
}
}

@jatin085

This comment has been minimized.

jatin085 commented Jan 25, 2017

@LaylaLiu, any ETA on when will this be fixed? We are blocked on this (Microsoft CRM team).

@LaylaLiu

This comment has been minimized.

Contributor

LaylaLiu commented Jan 25, 2017

Add @markdstafford@mikepizzo about the ETA.

robward-ms added a commit to robward-ms/odata.net that referenced this issue Feb 1, 2017

Issues
This pull request fixes issue OData#706.

Description
Consider owning type when adding/getting properties from the PropertyCacheHandler.
Unit tests are added to cover simple PropertyCacheHandler scenarios.

Checklist (Uncheck if it is not completed)
[ x ] Test cases added
[ x ] Build and test with one-click build and test script passed

Additional work necessary
No document change required.
@joshcomley

This comment has been minimized.

joshcomley commented Feb 1, 2017

The fix by @ArnoudRoo worked for me, I had to roll my own version. Is there any update on the ETA to have this fix in the official package?

@markdstafford

This comment has been minimized.

Member

markdstafford commented Feb 1, 2017

The PR (7f45fe6) from @robward-ms is the official fix; we need to spend some time looking through the PRs and issues that have built up from the 7.x release, but we will most likely release an official package later this month. Sorry I can't give you a more accurate estimate; depends on what we find that needs to be pulled in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment