MapODataRoute and ODataQueryOptions

2019-05-28 01:06发布

问题:

Im building a WebAPI OData solution that handles untyped entity objects, as described in this excellent post. Like that post, I define my EdmModel upfront, and use the MapODataRoute method and pass in the model to use:

config.Routes.MapODataRoute("odata", "odata", ModelBuilder.GetEdmModel());

However, this does not seem to work with ODataQueryOptions parameter in my methods:

Get(ODataQueryOptions query)
{
}

It gives the following error: The given model does not contain the type 'System.Web.Http.OData.IEdmEntityObject'. Parameter name: elementClrType

Is there any way to get ODataQueryOptions to work with MapODataRoute?

回答1:

You should build the ODataQueryOptions manually in your controller action in untyped mode. Sample code follows,

ODataPath path = Request.GetODataPath();
IEdmType edmType = path.EdmType;

IEdmType elementType = edmType.TypeKind == EdmTypeKind.Collection 
    ? (edmType as IEdmCollectionType).ElementType.Definition 
    : edmType;

// build the typeless query options using the element type.
ODataQueryContext queryContext = new ODataQueryContext(Request.GetEdmModel(), elementType);
ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, Request);


回答2:

Ive managed to do it as follows:

ODataPath path = Request.GetODataPath();
IEdmType edmType = path.EdmType;   

private ODataQueryOptions GetODataQueryOptions(IEdmType edmType)
    {
        IEdmModel model = Models.ModelBuilder.GetEdmModel();
        ODataQueryContext queryContext = new ODataQueryContext(model, edmType);
        ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, this.Request);

        return queryOptions;
    }

This works for most query options, but crashes with $select and $expand: The type 'Collection([Org.Microsoft.Product Nullable=False])' is not an entity type. Only entity types support $select and $expand. Is there a way to avoid this exception gracefully when a client tries to filter with $select and $expand, or should i just write something like

if (Request.RequestUri.Query.Contains("select")) { return errormessage }

Also, and more importantly, how would one apply these query options to an EdmEntityObjectCollection which gets returned in the first method?

queryOptions.ApplyTo(collectionProduct.AsQueryable()); // wont work...

(perhaps it is better practice to dynamically build your collection in regards to the query options anyway)