OData constraint with multiple extension levels does not work

Software used:

  • ASP.NET Web API 2.2
  • OData v4.0
  • OData Client for .NET (v 6.11)

Consider the following model:

User (UserId, Name)

UserMessage (UserMessageId, User, Message, DateRead)

Message (MessageId, MessageType, Title, Text)

MessageType (MessageTypeId, Name)

User has many UserMessages and UserMessage connects user and message and has some additional properties. The message has a MessageType property, which also has some properties.

And the following OData configuration:

var builder = new ODataConventionModelBuilder();

builder.EntitySet<User>("Users");
// Configure an containment for messages.
builder.EntityType<User>().ContainsMany(u => u.Messages);
builder.EntityType<UserMessage>()
builder.EntitySet<Message>("Messages");
builder.EntitySet<MessageType>("MessageTypes");

var edmModel = builder.GetEdmModel();

config.MapODataServiceRoute(
        routeName: "ODataRoute",
        routePrefix: null,
        model: edmModel);

      

Notes:

  • Message and MessageType must be configured as entities because we need to be able to add custom messages and message types using their respective controllers.
  • Custom messages are not displayed as a set of objects, but as a containment on an object set by Users.

The UserController uses the following method to process the content for messages:

[EnableQuery]       
public async Task<IQueryable<UserMessage>> GetMessages(int key)

      

When selecting all custom messages using the shell, everything works as expected:

/ Users (1) / messages

Return:

{
    "@odata.context":"https://host/$metadata#Users(1)/messages","value":[
    {
        "userId":1,"messageId":50,"dateRead":null,"userMessageId":481
    }]
}

      

And the post expansion also works:

/ Users (1) / messages? $ = Post extension

Return:

{
  "@odata.context":"https://host/$metadata#Users(1)/messages","value":[
    {
      "userId":1,"messageId":50,"dateRead":null,"userMessageId":481,"message":{
        "title":"Test","text":"Test","messageTypeId":1,"messageId":50
      }
    }
  ]
}

      

However, when extending the MessageType in Message, the request fails when deserializing on the client (using OData Client for .NET v6.11). Returned JSON:

{
  "@odata.context":"https://host/$metadata#Users(1)/messages","value":[
    {
      "userId":1,"messageId":50,"dateRead":null,"userMessageId":481,"message":{
        "title":"Test","text":"Test","messageTypeId":1,"messageId":50,"messageType":{
          "@odata.type":"#Domain.Message.MessageType","name":"General","messageTypeId":1
        }
      }
    }
  ]
}

      

Client error:

When writing the JSON response, the user model must be specified, and the object set and entity type must be passed. The ODataMessageWriter.CreateODataEntryWriter or ODataFeedAndEntrySerializationInfo method must be set to the ODataEntry or ODataFeed that is being written.

And the stacktrace:

[ODataException: When writing the JSON response, the user model must be specified and the object set and entity type must be passed to the ODataMessageWriter.CreateODataEntryWriter method, or the ODataFeedAndEntrySerializationInfo must be set to the ODataEntry or ODataFeed that is being written. ] Microsoft.OData.Core.ODataFeedAndEntryTypeContext.ValidateAndReturn (T value) +74 Microsoft.OData.Core.Evaluation.ODataConventionalEntityMetadataBuilder.ComputeId () +71 Microsoft.OData.Core.Evality.ODataContectedatautedEntuation Client.Materialization.MaterializerEntry.UpdateEntityDescriptor () +426 Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.ReadEntryCore () +310 Microsoft.OData.Client.Materialization.ODataFeed & feed, MaterializerEntry & entry) +149 Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.ReadNavigationLink () +91 Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.ReadEntry6Core () + TryReadFeedOrEntry (Boolean lazy, ODataFeed & feed, MaterializerEntry & entry) +149 Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.ReadNavigationLink () +91 Microsoft.OData.Client.Materialization.FeedAndapEntry .Materialization.d__0.MoveNext () +139 Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.Read () +68 Microsoft.OData.Client.Materialization.ODataEntityMaterializer.ReadImplementation () +113 Microsoft.OData.Client.MaterializeAtom.MoveNextInternal () +475 Microsoft.OData.Client.MaterializeAtom.MoveNext () +108 System.Linq.d__b11.MoveNext() +296 System.Linq.WhereSelectEnumerableIterator

2.MoveNext () +165 System.Collections.Generic.List 1..ctor(IEnumerable

1 collection) +536 System.Linq.Enumerable.ToList (source IEnumerable`1) +80

When requesting full metadata information for a url using "odata.metadata = full", the server returns the same error as the client:

HTTP/1.1 500 Internal Server Error
Content-Length: 3455
Content-Type: application/json; odata.metadata=full; charset=utf-8
Server: Microsoft-IIS/7.5
OData-Version: 4.0
X-Powered-By: ASP.NET
Date: Tue, 23 Jun 2015 09:47:20 GMT

{
  "error":{
    "code":"","message":"An error has occurred.","innererror":{
      "message":"When writing a JSON response, a user model must be specified and the entity set and entity type must be passed to the ODataMessageWriter.CreateODataEntryWriter method or the ODataFeedAndEntrySerializationInfo must be set on the ODataEntry or ODataFeed that is being written.","type":"Microsoft.OData.Core.ODataException","stacktrace":"   at Microsoft.OData.Core.ODataFeedAndEntryTypeContext.ValidateAndReturn[T](T value)\r\n   at Microsoft.OData.Core.Evaluation.ODataConventionalEntityMetadataBuilder.ComputeId()\r\n   at Microsoft.OData.Core.Evaluation.ODataConventionalEntityMetadataBuilder.get_ComputedId()\r\n   at Microsoft.OData.Core.Evaluation.ODataConventionalEntityMetadataBuilder.TryGetIdForSerialization(Uri& id)\r\n   at Microsoft.OData.Core.JsonLight.ODataJsonLightEntryAndFeedSerializer.WriteEntryStartMetadataProperties(IODataJsonLightWriterEntryState entryState)\r\n   at Microsoft.OData.Core.JsonLight.ODataJsonLightWriter.StartEntry(ODataEntry entry)\r\n   at Microsoft.OData.Core.ODataWriterCore.InterceptException(Action action)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperty(KeyValuePair`2 navigationPropertyToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperties(IDictionary`2 navigationPropertiesToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperty(KeyValuePair`2 navigationPropertyToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperties(IDictionary`2 navigationPropertiesToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)\r\n   at System.Web.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)\r\n   at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, 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.<BufferResponseContentAsync>d__13.MoveNext()"
    }
  }
}

      

We need to expand the messageType in the message because we need the data on the client.

Any suggestions?

+3


source to share





All Articles