Avinash Karat
Avinash Karat

Reputation: 41

OData - Restrict properties to be used in $filter

My requirement is to allow only a few properties to be used in OData $filter option. Here I have a student model, which contains a bunch of properties. I want only the 'name' property have the $filter capability enabled. But somehow it is not working. Can anybody please help me.

The following is my code

My model:

public class Student {

    public string Id { get; set; }

    public string Name { get; set; }

    public string AccessType { get; set; }

    public string SortOrder { get; set; }

    public string Status { get; set; }

}

My QueryValidator:

public class RestrictiveFilterByQueryValidator : FilterQueryValidator
{
    static readonly string[] allowedProperties = { "name" };

    public RestrictiveFilterByQueryValidator(DefaultQuerySettings defaultQuerySettings)
                                                : base(defaultQuerySettings)
    {

    }

    public override void ValidateSingleValuePropertyAccessNode(
        SingleValuePropertyAccessNode propertyAccessNode,
        ODataValidationSettings settings)
    {
        string propertyName = null;
        if (propertyAccessNode != null)
        {
            propertyName = propertyAccessNode.Property.Name;
        }

        if (propertyName != null && !allowedProperties.Contains(propertyName))
        {
            throw new ODataException(
                String.Format("Filter on {0} not allowed", propertyName));
        }
        base.ValidateSingleValuePropertyAccessNode(propertyAccessNode, settings);
    }

    public static implicit operator System.Web.Http.OData.Query.Validators.FilterQueryValidator(RestrictiveFilterByQueryValidator v)
    {
        throw new NotImplementedException();
    }
}

My custom queryable attribute:

public class MyQueryableAttribute : QueryableAttribute
{
    public override void ValidateQuery(HttpRequestMessage request, System.Web.Http.OData.Query.ODataQueryOptions queryOptions)
    {
        if (queryOptions.Filter != null)
        {
            queryOptions.Filter.Validator = new RestrictiveFilterByQueryValidator(new DefaultQuerySettings());
        }

        // HttpRequestMessage request, ODataQueryOptions queryOptions
        base.ValidateQuery(request, queryOptions);
    }
}

Finally my API controller method:

    [MyQueryable]
    public ActionResult<IEnumerable<Student>> GetAllStudent()
    {
        
    }

When I followed the above code, my normal $filter with valid properties also don't work as expected. I think I am missing something. Any help will be grateful.

Upvotes: 2

Views: 1358

Answers (1)

Chris Schaller
Chris Schaller

Reputation: 16554

Do not call the base implementation of the Validator if the property IS Valid.

It's not that obvious but the base implementation exists to format the error message in a standard way so you return nothing when it is valid and call the base only when it is NOT valid!

public override void ValidateSingleValuePropertyAccessNode(
    SingleValuePropertyAccessNode propertyAccessNode,
    ODataValidationSettings settings)
{
    string propertyName = null;
    if (propertyAccessNode != null)
    {
        propertyName = propertyAccessNode.Property.Name;
    }

    if (propertyName != null && !allowedProperties.Contains(propertyName))
    {
        base.ValidateSingleValuePropertyAccessNode(propertyAccessNode, settings);
    }
}

Upvotes: 1

Related Questions