Webapi: EnableQuery does not work at Method or Controller Level without setting global query options.

Created on 24 Dec 2017  路  11Comments  路  Source: OData/WebApi

Installed the Beta 1 of OData 7.0.0 for ASP.NET Core, but couldn't make it work.
Whenever I try to use $filter in the QueryString I get the error:
"The query specified in the URI is not valid. Could not find a property named 'Url' on type 'Edm.String'."
I made sure that 'Url' (in this specific casing, as well as other) is part of the Blog entity.

Assemblies affected

Microsoft.AspNetCore.OData 7.0.0-beta1
Microsoft.OData.Core (7.3.1)
My website uses also EF core, not sure if it's rellevant. If so -
Microsoft.EntityFrameworkCore.SqlServer (2.0.1)

Reproduce steps

  1. Add this to ConfigureServices method in Startup.cs:
    services.AddOData();
    services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("BloggingDatabase")));
    (Note that BloggingDatabase is the one used in the Getting Started of EF Core here: https://docs.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db)
  2. Add this to the Configure method in Startup.cs:
    var builder = new ODataConventionModelBuilder(app.ApplicationServices);
    builder.EntitySet("Products");
    builder.EntitySet("Blogs").EntityType.Filter(Microsoft.AspNet.OData.Query.QueryOptionSetting.Allowed);

        app.UseMvc(routeBuilder=>routeBuilder.MapODataServiceRoute("ODataRoute",null,builder.GetEdmModel()));
        app.UseMvc(routeBuilder => routeBuilder.EnableDependencyInjection());
    
  3. Create a new Controller named BlogsController:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using ODataTest.Models;
    using Microsoft.AspNet.OData;

namespace ODataTest.Controllers
{
[Produces("application/json")]
[Route("api/Blogs")]
[EnableQuery(AllowedQueryOptions =Microsoft.AspNet.OData.Query.AllowedQueryOptions.All)]
public class BlogsController : ODataController
{
private readonly BloggingContext _context;

    public BlogsController(BloggingContext context)
    {
        _context = context;
    }

    // GET: api/Blogs
    [HttpGet]
    [EnableQuery(AllowedQueryOptions = Microsoft.AspNet.OData.Query.AllowedQueryOptions.All)]
    public IEnumerable<Blog> GetBlog()
    {
        return _context.Blog;
    }       
}

}

  1. Run scaffolding on the DB to create the model classes. As a result, a context and a Blog class (also a Post class) are generated from the DB. This is the Blog class:
    using System;
    using System.Collections.Generic;

namespace ODataTest.Models
{
public partial class Blog
{
public Blog()
{
Post = new HashSet();
}

    public int BlogId { get; set; }
    public string Url { get; set; }

    public ICollection<Post> Post { get; set; }
}

}

When running the app end navigating to:
http://localhost:59924/api/blogs

The result is:
[{"blogId":1,"url":"http://blogs.msdn.com/dotnet","post":[]},{"blogId":2,"url":"http://blogs.msdn.com/webdev","post":[]},{"blogId":3,"url":"http://blogs.msdn.com/visualstudio","post":[]}]

Expected result

When navigating to:
http://localhost:59924/api/blogs?$filter=contains(Url,%27webdev%27)

The expected result is:
[{"blogId":2,"url":"http://blogs.msdn.com/webdev","post":[]}]

Actual result

This error appears:
"The query specified in the URI is not valid. Could not find a property named 'Url' on type 'Edm.String'."

Additional Details

It's interesting to note that when the EnableQuery attribute was applied only at the controller level and not on the Action itself, the error message was different, and stated that $filter cannot be used. I'm not sure if this is a bug or by design.

P3 featurnetcore question

Most helpful comment

I have same problem with $select.
This help me:
routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

app.UseMvc(routeBuilder =>
{
    routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
    routeBuilder.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());
    routeBuilder.EnableDependencyInjection();
});

But with $filter all work without this line.

All 11 comments

Case sensitive. Try:
http://localhost:59924/api/blogs?$filter=contains(url,%27webdev%27)

Nope, got the exact same message...

I have same problem with $select.
This help me:
routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

app.UseMvc(routeBuilder =>
{
    routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
    routeBuilder.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());
    routeBuilder.EnableDependencyInjection();
});

But with $filter all work without this line.

Yes! That did it! Thanks!

Is it somewhere in the docs and I missed it?

I found it here: http://odata.github.io/WebApi/#13-01-modelbound-attribute
$filter work for me, because I have:
builder.EntitySet<Categories>("Categories").EntityType.HasKey(s => s.CategoryId).Filter(Microsoft.AspNet.OData.Query.QueryOptionSetting.Allowed);

Why this line didn't help you with $filter... interesting....:
builder.EntitySet("Blogs").EntityType.Filter(Microsoft.AspNet.OData.Query.QueryOptionSetting.Allowed);

With $select I had another error - cannot be used

"The query specified in the URI is not valid. The property 'Name' cannot be used in the $select query option."

@memilavi - Yep, that is a new requirement for WebApi 6.0 and therefore 7.0 as @sorcerb pointed out.

Seems like there is still an issue to investigate here as your model was set to allow all query options so let's leave the issue open to track that. I'd like to change the title though if that's OK.

Sure, go ahead.

@memilavi - I tried with both the EnableQuery on the controller and the controller & action and filtering worked without the global query option as long as the model defined filter as enabled. So this should work expected. Couple of questions:

1.) I noticed you have an "[Route("api/Blogs")]" attribute on the controller and the example Url contains api/Blogs. This returned a 500 for me, I used a Url without api, i.e. http://localhost:59924/blogs because the prefix parameter to MapODataServiceRoute was null. Did you try with or without "api"?

2.) Is there more to your controller and/or can you verify that the GetBlog() method is hit using a breakpoint?

for me with version 7.0.1 this

routes.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

in

app.UseMvc(routes => { ... }

is not working anymore without adding this to each controller

[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]

Is this normal ? How can i set by default for all my controllers thoses options ?
Thanks

This help me:
routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

If you use
app.UseOData("odata", "odata", GetEdmModel());
instead of

app.UseMvc(routeBuilder =>
{
    routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());
    ...
}

there is no need for explicit calling the line above just for OData routes

I found it here: http://odata.github.io/WebApi/#13-01-modelbound-attribute

This link has now moved to https://docs.microsoft.com/en-us/odata/webapi/modelbound-attribute (shame Microsoft never seem to add redirects when they reorganise documentation)

Was this page helpful?
0 / 5 - 0 ratings