"The property {property} does not exist on type {type}" - but it does. OData configuration issue?

2

I have a Blazor WASM application that has an OData back-end. I'm trying to configure the NavigationProperty of one of my models so that I can use the $expand= query parameter to return more data but I keep getting the following error when trying to make a PATCH request (GET works just fine):

Microsoft.OData.ODataException: The property 'JobId' does not exist on type 'Coin.ODataOrderHeader'. Make sure to only use property names that are defined by the type or mark the type as open type.

But it does exist! Not just in the model:

public partial class ODataOrderHeader
{
        [Key]
        public int OrderId { get; set; }

        [Column("JobID")]
        [ForeignKey("Job")]
        public int JobId { get; set; }
        ...
        [System.Text.Json.Serialization.JsonPropertyName("Job")]
        public virtual Jobs Job { get; set; }
}

But in the $metadata document as well:

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="Coin" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            ...
            <EntityType Name="ODataOrderHeader">
                <Key>
                    <PropertyRef Name="OrderId" />
                </Key>
                <Property Name="OrderId" Type="Edm.Int32" Nullable="false" />
                <Property Name="JobId" Type="Edm.Int32" />
                ...
                <NavigationProperty Name="Job" Type="Coin.Jobs">
                    <ReferentialConstraint Property="JobId" ReferencedProperty="JobId" />
                </NavigationProperty>
            </EntityType>
            ...
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Here is the code that creates the model:

        private IEdmModel GetEdmModel()
        {
            var builder = new ODataConventionModelBuilder();
            builder.Namespace = "Coin";
            builder.ContainerName = "CoinContainer";
            ...
            var orders = builder.EntitySet<ODataOrderHeader>("Orders");
            return builder.GetEdmModel();
        }

I should probably point out, ODataOrderHeader is more of a DTO type whereas Jobs is an EF scaffolded type.

Here is the Simple.OData.Client code that calls the API:

    private async void UpdateItem()
    {
        ODataClient client = new ODataClient(new ODataClientSettings(HttpClient, new Uri("odata", UriKind.Relative)));

        await client.For<ODataOrderHeader>("Orders")
            .Key(currentOrder.OrderId)
            .Set(currentOrder)
            .UpdateEntryAsync();
    }

And here's the controller action that the above code is calling:

        [ODataRoute("/orders({key})")]
        public async Task<IActionResult> Patch([FromODataUri] int key, Delta<ODataOrderHeader> order)
        {
            if (!ModelState.IsValid)
                return BadRequest();

            ...
        }

And lastly, the error message in its entirety:

Unhandled Exception:
Microsoft.OData.ODataException: The property 'JobId' does not exist on type 'Coin.ODataOrderHeader'. Make sure to only use property names that are defined by the type or mark the type as open type.
  at Microsoft.OData.WriterValidationUtils.ValidatePropertyDefined (Microsoft.OData.PropertySerializationInfo propertyInfo, System.Boolean throwOnUndeclaredProperty) <0x61a9028 + 0x00098> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WritePropertyInfo (Microsoft.OData.ODataPropertyInfo propertyInfo, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6120d78 + 0x000f8> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperty (Microsoft.OData.ODataProperty property, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x61203e8 + 0x00018> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperties (Microsoft.OData.Edm.IEdmStructuredType owningType, System.Collections.Generic.IEnumerable`1[T] properties, System.Boolean isComplexValue, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6011c28 + 0x00048> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource (Microsoft.OData.ODataResource resource) <0x5ef5478 + 0x003d6> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass121_0.<WriteStartResourceImplementation>b__0 () <0x5ed80f0 + 0x00082> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.InterceptException (System.Action action) <0x5ed3f20 + 0x00042> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation (Microsoft.OData.ODataResource resource) <0x5ed3a78 + 0x00076> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass49_0.<WriteStartAsync>b__0 () <0x5ed3628 + 0x0000c> in <filename unknown>:0 
  at Microsoft.OData.TaskUtils.GetTaskForSynchronousOperation (System.Action synchronousOperation) <0x5ed34e0 + 0x0000a> in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---

  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryPropertiesAsync (Microsoft.OData.ODataWriter entryWriter, Microsoft.OData.ODataResource entry, System.Collections.Generic.IDictionary`2[TKey,TValue] links) <0x5ed2260 + 0x000f2> in <filename unknown>:0 
  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryContentAsync (System.String method, System.String collection, System.String commandText, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5477750 + 0x0049c> in <filename unknown>:0 
  at Simple.OData.Client.RequestWriterBase.CreateUpdateRequestAsync (System.String collection, System.String entryIdent, System.Collections.Generic.IDictionary`2[TKey,TValue] entryKey, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5814b98 + 0x0020c> in <filename unknown>:0 
  at Simple.OData.Client.RequestBuilder.UpdateRequestAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577cd28 + 0x00386> in <filename unknown>:0 
  at Simple.OData.Client.ODataClient.UpdateEntryAsync (Simple.OData.Client.FluentCommand command, System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577bcc8 + 0x00162> in <filename unknown>:0 
  at Simple.OData.Client.BoundClient`1[T].UpdateEntryAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x576d9a0 + 0x00230> in <filename unknown>:0 
  at Coin.Client.Pages.OrderEdit.UpdateItem () [0x000ac] in C:\Users\trichardson\source\Workspaces\Corsi\COIN2\Client\Pages\OrderEdit.razor:393 
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) <0x6547930 + 0x0000c> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) <0x65478e0 + 0x00022> in <filename unknown>:0 
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x3112fc8 + 0x00100> in <filename unknown>:0 
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x310b7d8 + 0x00010> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () <0x5743290 + 0x00038> in <filename unknown>:0 
  at System.Threading.ThreadPoolWorkQueue.Dispatch () <0x39a89b8 + 0x00102> in <filename unknown>:0 
  at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () <0x39a4578 + 0x00000> in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: Microsoft.OData.ODataException: The property 'JobId' does not exist on type 'Coin.ODataOrderHeader'. Make sure to only use property names that are defined by the type or mark the type as open type.
  at Microsoft.OData.WriterValidationUtils.ValidatePropertyDefined (Microsoft.OData.PropertySerializationInfo propertyInfo, System.Boolean throwOnUndeclaredProperty) <0x61a9028 + 0x00098> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WritePropertyInfo (Microsoft.OData.ODataPropertyInfo propertyInfo, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6120d78 + 0x000f8> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperty (Microsoft.OData.ODataProperty property, Microsoft.OData.Edm.IEdmStructuredType owningType, System.Boolean isTopLevel, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x61203e8 + 0x00018> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightPropertySerializer.WriteProperties (Microsoft.OData.Edm.IEdmStructuredType owningType, System.Collections.Generic.IEnumerable`1[T] properties, System.Boolean isComplexValue, Microsoft.OData.IDuplicatePropertyNameChecker duplicatePropertyNameChecker, Microsoft.OData.Evaluation.ODataResourceMetadataBuilder metadataBuilder) <0x6011c28 + 0x00048> in <filename unknown>:0 
  at Microsoft.OData.JsonLight.ODataJsonLightWriter.StartResource (Microsoft.OData.ODataResource resource) <0x5ef5478 + 0x003d6> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass121_0.<WriteStartResourceImplementation>b__0 () <0x5ed80f0 + 0x00082> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.InterceptException (System.Action action) <0x5ed3f20 + 0x00042> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore.WriteStartResourceImplementation (Microsoft.OData.ODataResource resource) <0x5ed3a78 + 0x00076> in <filename unknown>:0 
  at Microsoft.OData.ODataWriterCore+<>c__DisplayClass49_0.<WriteStartAsync>b__0 () <0x5ed3628 + 0x0000c> in <filename unknown>:0 
  at Microsoft.OData.TaskUtils.GetTaskForSynchronousOperation (System.Action synchronousOperation) <0x5ed34e0 + 0x0000a> in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---

  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryPropertiesAsync (Microsoft.OData.ODataWriter entryWriter, Microsoft.OData.ODataResource entry, System.Collections.Generic.IDictionary`2[TKey,TValue] links) <0x5ed2260 + 0x000f2> in <filename unknown>:0 
  at Simple.OData.Client.V4.Adapter.RequestWriter.WriteEntryContentAsync (System.String method, System.String collection, System.String commandText, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5477750 + 0x0049c> in <filename unknown>:0 
  at Simple.OData.Client.RequestWriterBase.CreateUpdateRequestAsync (System.String collection, System.String entryIdent, System.Collections.Generic.IDictionary`2[TKey,TValue] entryKey, System.Collections.Generic.IDictionary`2[TKey,TValue] entryData, System.Boolean resultRequired) <0x5814b98 + 0x0020c> in <filename unknown>:0 
  at Simple.OData.Client.RequestBuilder.UpdateRequestAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577cd28 + 0x00386> in <filename unknown>:0 
  at Simple.OData.Client.ODataClient.UpdateEntryAsync (Simple.OData.Client.FluentCommand command, System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x577bcc8 + 0x00162> in <filename unknown>:0 
  at Simple.OData.Client.BoundClient`1[T].UpdateEntryAsync (System.Boolean resultRequired, System.Threading.CancellationToken cancellationToken) <0x576d9a0 + 0x00230> in <filename unknown>:0 
  at Coin.Client.Pages.OrderEdit.UpdateItem () [0x000ac] in C:\Users\trichardson\source\Workspaces\Corsi\COIN2\Client\Pages\OrderEdit.razor:393 
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) <0x6547930 + 0x0000c> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) <0x65478e0 + 0x00022> in <filename unknown>:0 
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x3112fc8 + 0x00100> in <filename unknown>:0 
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x310b7d8 + 0x00010> in <filename unknown>:0 
  at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () <0x5743290 + 0x00038> in <filename unknown>:0 
  at System.Threading.ThreadPoolWorkQueue.Dispatch () <0x39a89b8 + 0x00102> in <filename unknown>:0 
  at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () <0x39a4578 + 0x00000> in <filename unknown>:0 
Uncaught ExitStatusThe program '' has exited with code -1 (0xffffffff).

Is there a configuration error I'm missing or is there something wrong with the controller action?

c#
.net-core
odata
blazor
simple.odata.client
asked on Stack Overflow Aug 10, 2020 by Bigg_T76 • edited Aug 10, 2020 by Bigg_T76

1 Answer

0

For anyone that stumbles across this in the future, I was able to uncover a little more information.

Firstly, by adding some data annotations [IgnoreDataMember] on my Jobs class and by adding {IgnoreUnmappedProperties = true} when instantiating the ODataClient, I was able to get a different error. Something along the lines of: The key 'JobId' does not exist in the dictionary.

For context, I'm trying to do what OData refers to as a "deep update". I want to update a child entity while updating the parent entity. However, Simple.OData.Client does not support deep updates or deep linking or deep creation. Here's a 5 year old question from Simple.OData.Client's GitHub page that talks about this and unfortunately, it would appear that development of this package has ceased ("Future of Simple.OData.Client" and "Project Dead?"). Since it doesn't support "deep updates", it doesn't know how to generate the request URL which is why my PATCH request was failing.

answered on Stack Overflow Aug 14, 2020 by Bigg_T76

User contributions licensed under CC BY-SA 3.0