0
votes

I am having trouble getting a complex object to serialize. I have found few examples on this & need some help. I have a POCO class that implements an Interface for a Class Property, as below...

  • The problem is...OData cannot serialize the IObjectState Property

HOW DO I MAKE ODATA AWARE of COMPLEX TYPES IN PROPERTIES?

  • Please keep in mind the IObjectState is a non-entity class & has no key

POCO CLASS:

public class ShakeoutDocument : Document, IDocument, IStateful
{
    public IObjectState ObjectState { get; set; } //<-- This property contains the instance (below)

    public int ShakeoutId { get; set; }

    public string SchedulingBatch { get; set; }

    [...] //<-- Other properties are omitted for brevity
}

IObjectState Property CLASS:
Here is an example of a concrete IObjectState class...

// Example of an IObjectState Instance
public class New : IObjectState
{
    public List<IObjectStateEvent> Events { get; set; }

    public string Name { get; set; }
}

EDM CONFIGURATION: As a BOUND Function:
Using this EDM Model configuration & Api...

modelBuilder.EntitySet<ShakeoutDocument>("ShakeoutDocument");

[HttpGet]
public ShakeoutDocument Get([FromODataUri] int id)
{
    var provider = Application.ShakeoutDocumentProvider as ShakeoutDocumentProvider;
    var entity = provider.Get(id);

    return entity;
}

Generates the following exception...

"The given model does not contain the type 'New'."

EDM CONFIGURATION: As a UNBOUND Function:
Using this EDM Model configuration & Api...

var getShakeoutDocument = modelBuilder.Function("GetShakeoutDocument").ReturnsFromEntitySet<ShakeoutDocument>("ShakeoutDocument");
getShakeoutDocument.Parameter<int>("id");

[ODataRoute("GetShakeoutDocument(id={id})")]
public IHttpActionResult GetShakeoutDocument([FromODataUri] int id)
{
    var provider = Application.ShakeoutDocumentProvider as ShakeoutDocumentProvider;
    var entity = provider.Get(id);

    return Ok(entity);
}

Generates the following exception...

"The given model does not contain the type 'New'."

UPDATING THE EDM CONFIGURATION: with concrete New:
Updating the EDM Model configuration with...

modelBuilder.AddComplexType(typeof(New));

Generates the following exception...

"A value was encountered that has a type name that is incompatible with the metadata. The value specified its type as 'New', but the type specified in the metadata is 'IObjectState'."

Any help is appreciated.

1

1 Answers

0
votes

Okay, after much searching, I found the answer here. Basically, you have to describe to OData all the possible implementations of any given Complex Property...even for UNBOUND FUNCTIONS.

Unbound really SHOULD imply standard WebApi is being used...but this obviously isn't the case....as this object serializes FINE using standard WebApi, but fails using OData.

private static  IEdmModel GetEdmModel()
{
    var modelBuilder = new ODataConventionModelBuilder();

    // ENTITY SETS: Normal
    modelBuilder.EntitySet<tblDbcCommunications>("Communication");
    modelBuilder.EntitySet<tblDbcItems>("Item");
    modelBuilder.EntitySet<Meter>("Meter");
    modelBuilder.EntitySet<Product>("Product");
    modelBuilder.EntitySet<WarehouseMeter>("WarehouseMeter");
    modelBuilder.EntitySet<Shakeout>("Shakeout");
    modelBuilder.EntitySet<tblDbcCircuitOwner>("tblDbcCircuitOwner");

    // ENTITY SETS: Complex
    ConfigureComplexEntitySet(modelBuilder, modelBuilder.EntitySet<ShakeoutDocument>("ShakeoutDocument"));

    // KEY BINDINGS
    modelBuilder.EntityType<WarehouseMeter>().HasKey(x => x.METER_ID);

    // UNBOUND FUNCTIONS
    //  - Action    = Post
    //  - Function  = Get

    // WarehouseMeter
    var findPulseMeter = modelBuilder.Function("FindWarehouseMeter").ReturnsCollectionFromEntitySet<WarehouseMeter>("WarehouseMeter");
    findPulseMeter.Parameter<string>("search");

    // ShakeoutDocument
    var getShakeoutDocument = modelBuilder.Function("GetShakeoutDocument").ReturnsFromEntitySet<ShakeoutDocument>("ShakeoutDocument");
    getShakeoutDocument.Parameter<int>("id");

    // Product
    var listProduct = modelBuilder.Function("ListProducts").ReturnsCollectionFromEntitySet<Product>("Product");

    return modelBuilder.GetEdmModel();
}

private static EntitySetConfiguration<ShakeoutDocument> ConfigureComplexEntitySet(ODataConventionModelBuilder modelBuilder, EntitySetConfiguration<ShakeoutDocument> configuration)
{

    // Collection Properties
    configuration.EntityType.CollectionProperty(x => x.Seals);
    configuration.EntityType.CollectionProperty(x => x.Details);

    // Complex Properties
    configuration.EntityType.ComplexProperty(x => x.ObjectState);

    // Object State
    var newObjectState = modelBuilder.ComplexType<New>();
    newObjectState.DerivesFrom<IObjectState>();

    var submittedObjectState = modelBuilder.ComplexType<Submitted>();
    submittedObjectState.DerivesFrom<IObjectState>();

    // Object State Event
    var isNewObjectStateEvent = modelBuilder.ComplexType<IsNew>();
    isNewObjectStateEvent.DerivesFrom<IObjectStateEvent>();

    var isSubmittedObjectStateEvent = modelBuilder.ComplexType<IsSubmitted>();
    isSubmittedObjectStateEvent.DerivesFrom<IObjectStateEvent>();

    return configuration;
}