Limit OData $filter by property in Web API

2019-07-11 14:59发布

问题:

I want to only allow some properties to be used in OData query $filter option.

I see that there an AllowedOrderByProperties parameter to EnableQueryAttribute, but I didn't find another for $filter. Did I just miss it? If not, what would it take to implement it?

回答1:

You can try the following:

once you have the builder, you can list the properties of the entitySet then you can mention if the field is filterable or not.

var entityTypeConfig = builder.EntitySet<SomeType>("SomeType").EntityType;
entityTypeConfig.Property(x => x.SomeField);
entityTypeConfig.Property(x => x.SomeField2).IsNotFilterable().IsNonFilterable();
// not sure what is the difference between them

and in the controller action (the httpGet for example) add

options.Filter.Validate(allowedOptions);

in case a field is not filterable this would throw an exception.



回答2:

I think you are going to be rolling your own filter validation since there isn't any built-in language around what you are filtering. This may or may not be helpful for you but I would recommend using a ModelBinder to perform your validation so when your controller methods are run, you've already validated the content of all parameters. My suggestion would be to return an object from your ModelBinder that meets whatever your business needs are in your app. You can certainly use the OData constructs to help you do that. Here's a snippet of code from our system that starts this process. It may be helpful to get you going on your own Binder.

private T CreateQueryOptions<T>(string url, [CallerMemberName] string caller = null) where T : class
{
    var httpRequest = new HttpRequestMessage(HttpMethod.Get, url);
    ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.EntitySet<T>(caller);
    var odata =  new ODataQueryOptions<T>(new ODataQueryContext(modelBuilder.GetEdmModel(), typeof(T)), httpRequest);
    // rest of your code here to validate OData parameters  Generics may not be appropriate for you.
}

But this works for me in a real system with 100's of millions of calls / day.