I'm trying to use WCF OData Services 5.2 to publish service methods, which should return a collection of derived types (POCO objects):
public class WcfDataService1 : DataService<MyProvider>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
config.SetServiceActionAccessRule("*", ServiceActionRights.Invoke);
}
[WebGet]
public List<Vehicle> GetStuff()
{
var c = new List<Vehicle>()
{
new Motorbike() {Id = 1},
new Car() {Id = 2}
};
return c;
}
}
public class MyProvider
{
public IQueryable<Car> Cars { get; set; }
public IQueryable<Motorbike> Motorbikes { get; set; }
}
[DataServiceEntity]
[DataServiceKey("Id")]
public abstract class Vehicle
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Motorbike : Vehicle
{
public int MaxSpeed { get; set; }
}
public class Car: Vehicle
{
public int NumberOfTyres { get; set; }
}
I receive the following exception: Service operation 'System.Collections.Generic.List`1[ODataV3.Vehicle] GetStuff()' produces instances of type 'ODataV3.Vehicle', but having a single entity set for that type is required.
In case I add an entity set to my context, it cause a different exception: Property 'Vehicles' and 'Cars' are IQueryable of types 'ODataV3.Vehicle' and 'ODataV3.Car' and type 'ODataV3.Vehicle' is an ancestor for type 'ODataV3.Car'. Please make sure that there is only one IQueryable property for each type hierarchy.
Without the service method I get the correct metadata with the expected basetype attributes.
Is there any way to implement my GetStuff() method and have all the necessary OData metadata? I tried to combine the attributes on the base/inherited types, no success. I wouldn't write the metadata manually in a WebAPI project (extended with additional OData modules).
This is currently not possible. Each entity type must have exactly one entity set (applies to service operations, doesn't apply in general, but mostly it's only possible with custom providers). In your case the entity type Vehicle has two entity sets.
Typically such a service would be modeled by returning a single entity set Vehicles (of type Vehicle) which returns everything. On the client you can restrict to Motorbike using the V3 type segment feature: ~/Vehicles/NS.Motorbike
It is also possible to provide queryable service operations which then act like the entity sets (almost), for a specific type on the server (if that is required).