Search code examples
c#odataasp.net-web-apiasp.net-web-api2

Exclude implemented interfaces in ODataConventionModelBuilder


I'm having a weird issue with Web API 2 and OData v3, specifically the ODataConventionModelBuilder. I have the following code in my WebApiConfig.cs:

// Web API configuration and services
var builder = new ODataConventionModelBuilder();

// Adding all the entity sets here, then complex types, custom actions, ...
builder.EntitySet<Address>("Addresses");
/* ... */

builder.AddComplexType(typeof(CustomerSearchResultDto));
/* ... */

var customerSearchAction = builder.Entity<Customer>().Collection.Action("Search");
        patientSearchAction.Parameter<string>("pattern");
        patientSearchAction.Parameter<bool>("searchDeactivated");

// These are the interfaces that some entities implement. These MUST NOT be put into the model
var interfaces = typeof(ICustomer).Assembly.GetTypes().Where(t => t.IsInterface).ToArray();
builder.Ignore(interfaces);

// Building models
var model = builder.GetEdmModel();
config.Routes.MapODataServiceRoute("odata", "odata", model);

The models builds fine without exceptions. But the interfaces, that some entities implement, get converted to complex types, which of course is nonsensical and causes quite some namespace confusion on the client side. Here's an extract from the metadata generated (service:1111/$metadata)

<ComplexType Name="IAddress">
    <Property Name="Street1" Type="Edm.String" />
    <Property Name="Street2" Type="Edm.String" />
    <Property Name="Zip" Type="Edm.String" />
    <Property Name="City" Type="Edm.String" />
    <Property Name="Country" Type="Edm.String" />
</ComplexType>

I also tried to use builder.Ignore<IAddress>, but to no avail. What am I doing wrong?


Solution

  • I found a better solution. In the WebApiConfig.cs I do for every entity:

    builder.EntitySet<Address>("Addresses").EntityType.DerivesFromNothing();
    

    If the entities derive from another, I use the DerivesFrom() method. To avoid namespace clashes with my complex types, I use DTOs. Since I have a lot of them, I just batch add them like this (using reflection):

    var builderMethod = builder.GetType().GetMethod("ComplexType");
    foreach (var type in typeof (WebApiConfig).Assembly.GetTypes().Where(x => x.Name.EndsWith("Dto")))
    {
        var genericMethod = builderMethod.MakeGenericMethod(type);
        genericMethod.Invoke(builder, null);
    }
    

    This works pretty well.