Skip to content

InvalidOperationException: Cannot use 'Microsoft.AspNet.OData.Routing.ODataRoute' with Endpoint Routing. #1707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
grahamehorner opened this issue Dec 11, 2018 · 23 comments
Assignees
Milestone

Comments

@grahamehorner
Copy link

I'm trying to use ODATA with the current ASPNETCORE netcoreapp2.2 web template; I'm seeking the following at start up of the project.

InvalidOperationException: Cannot use 'Microsoft.AspNet.OData.Routing.ODataRoute' with Endpoint Routing.

@KanishManuja-MS
Copy link
Contributor

@grahamehorner Can you please give us more info on how to reproduce this?

@SiberaIndustries
Copy link
Contributor

Same issue here,

I've migrated my aspnetcore web api from 2.1 to 2.2.
The exception occurs when the app starts up at the app.UseMvc(..) call in the Configure method.

Currently I keep the Endpoint Routing feature disabled with the options.EnableEndpointRouting = false option.

This is a shrinked snipped of my implementation:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcCore(options =>
    {
        options.EnableEndpointRouting = false; // TODO: Remove when OData does not causes exceptions anymore
    })
        .AddAuthorization()
        .AddDataAnnotations()
        .AddJsonFormatters(options => options.ReferenceLoopHandling = ReferenceLoopHandling.Ignore)
        .AddCors()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddApiVersioning(options =>
    {
        options.ReportApiVersions = true;
        options.AssumeDefaultVersionWhenUnspecified = true;
    });
    
    services.AddOData().EnableApiVersioning();
    services.AddODataApiExplorer(options =>
    {
        options.GroupNameFormat = "'v'VVV"; // 'v'major[.minor][-status]
        options.SubstituteApiVersionInUrl = true;
    });
}

public void Configure(IApplicationBuilder app, IApiVersionDescriptionProvider provider, VersionedODataModelBuilder modelBuilder)
{
    app.UseMvc(routebuilder =>
    {
        modelBuilder.ModelBuilderFactory = () => new ODataConventionModelBuilder();
        routebuilder.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
        routebuilder.MapVersionedODataRoutes("odata", "api", modelBuilder.GetEdmModels());
    });
}

@grahamehorner
Copy link
Author

@Discjoggy yes, your correct I can confirm the above; if I use the .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); all seems to work, but I'd prefer to use .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); not sure what the breaking changes is ?

@davidfowl
Copy link
Contributor

Yes this is an intentional breaking change with a way to opt into the old behavior. Subclassing route is no longer a thing we expect frameworks to do moving forward.

cc @rynowak @JamesNK

@phatcher
Copy link

@davidfowl Does this imply a task for the OData team to update their work to fit in?

@rbugginsvia
Copy link

I've just seen this same behaviour after attempting a migrate to 2.2 - what needs to be looked at to address "Subclassing route is no longer a thing we expect frameworks to do moving forward."? thanks

@commonsensesoftware
Copy link

@phatcher - yes, this is definitely a task for the OData team. I'd be interested in sync'ing with you guys on the design offline (@chrimart internally). I've continuously had to reimplement several parts of the internal OData routing and other matching bits for API versioning. A key change in Endpoint Routing is that policies are composable, which wasn't possible in the legacy routing system. This made it difficult to build extensions on top of each other. For example, API versioning has to replace both the built-in and OData implementations of the old IActionSelector interface. The new IEndpointMatcherPolicy allows multiple policies to whittle down to a final result. In the past, OData has been painful for me in this regard because all previous action selection implementation (back to 5.9.x on Web API) always assume that you can only get zero or one answers from the EDM. In the API versioning world, it's possible to have two different OData actions, maybe even from different EDMs, with the same route (e.g. OData path), but are disambiguated by API version. It would be great to have a design from the OData team that doesn't require me to keep forking the implementation. There are likely other extension providers that could benefit from that as well.

One that note, @rynowak @JamesNK, one thing we didn't discuss in the design review is removing or replacing a policy. Is that a supported scenario? If OData team eventually creates an IEndpointMatcherPolicy, but it doesn't meet my need, can I replace or otherwise remove it? What would be the alternative? Fork the implementation, but give it a higher MatcherPolicy.Order than the original?

@Discjoggy I'm already in the process of supporting Endpoint Routing in API Versioning. That will include support for OData. I expect to have a 3.1 Beta release available within the next week or so.

@JamesNK
Copy link

JamesNK commented Dec 19, 2018

MatcherPolicy implementations are registered via DI. You have various options:

  1. You could not register their policy on startup
  2. They could implement their policy so that it took options injected DI, and the way their policy worked could be customize via setting options
  3. An alternative to options could be to inherit from their policy, override methods, and register your implementation instead of theirs.

I think option 2, setting options, is the best user experience.

@JamesNK
Copy link

JamesNK commented Dec 19, 2018

@Discjoggy yes, your correct I can confirm the above; if I use the .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); all seems to work, but I'd prefer to use .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); not sure what the breaking changes is ?

To only disable endpoint routing you can leave CompatibilityVersion.Version_2_2 on, and set MvcOptions.EnableEndpointRouting = false.

@rynowak
Copy link
Contributor

rynowak commented Dec 19, 2018

If you need to collaborate with OData, I'd really suggest defining a single matcher policy that delegates to a service/services

@commonsensesoftware
Copy link

@JamesNK - thanks. These all make sense. I try really hard to make API versioning bolt-on with "in addition to.." as opposed to "instead of..." semantics.

@commonsensesoftware
Copy link

@rynowak - that's what I'm hoping for. I've already replaced their routing mechanism with something that more closely resembles how Attribute Routing works. This is possible because OData has very strong route template conventions. I already had to build out the path templates for the API Explorer. I sprinkled a little refactoring on it and now I fix-up all of the OData ActionDescriptor instances with a new ODataAttributeRouteInfo:

public class ODataAttributeRouteInfo : AttributeRouteInfo
{
    public ODataAttributeRouteInfo()
    {
        SuppressLinkGeneration = true;
        SuppressPathMatching = true;
    }
    
    public ODataPathTemplate ODataTemplate { get; set; }
}

The ODataPathTemplate is very similar to how the RouteTemplate class works. Having the OData template parsed and usable on the correct actions makes things faster for all future lookups and is much easier to work with.

Up to this point, the OData implementation on ASP.NET Core seems to be mostly a port from Web API and didn't go through a reimagining of what could be possible on the new platform - IMO. I would welcome any discussion with the OData team because I would prefer not to own any of the routing infrastructure stuff. Unfortunately, I haven't been able to make API versioning work without a serious rework of a few critical pieces of routing infrastructure. Perhaps supporting Endpoint Routing will be the opportunity to have a melding of minds and converge some of these efforts.

@commonsensesoftware
Copy link

I thought I'd share an update on this topic. Thanks to @rynowak and @JamesNK I was able to create a compliant EndpointDataSource for OData. As I went further down the proverbial rabbit hole, it became clear that I would have to refactor a consider amount of the OData routing subsystem. That is simply more work and ownership than I'm willing to take on for API versioning. API Versioning 3.1 now supports Endpoint Routing, but when used in conjunction with OData, the legacy routing system must continue be used as noted above.

@markdstafford, @madansr7 I'm happy to share what I've done so far as well as other routing-related changes I've had to make in order to enable API Versioning with OData. There are a number of things that could be lifted and shifted over to the OData repo. Ideally, I'd like to own the least amount possible as it relates to the routing system.

Feel free to reach out if you're interested in sync'ing up. I'm guessing that most people are out of the office for the next couple of weeks during the holidays. I presume that any melding of minds would be some time in January? At minimum, I'd be interested in understanding your roadmap if you're going to support Endpoint Routing so that I can coordinate support on my side as appropriate.

Thanks

cc @raheph

@akorchev
Copy link

Does this issue also cause the incompatibility of OData with .NET Core 3? Do you guys plan to support .NET Core 3 when it officially releases?

@jhgbrt
Copy link

jhgbrt commented May 22, 2019

Any updates on this?

@pistonexia
Copy link

Any updates on this? We have a service running that will take a penalty if endpoint routing is disabled but yet we still want odata.

@mikepizzo mikepizzo added this to the 7.2 milestone Jun 3, 2019
@mikepizzo
Copy link
Member

We plan to have a release of WebAPI OData out around the end of the month. We'll look at this for that release, but it appears to be a larger and more fundamental change that may have to wait for our .NET Core 3 support.

@RamjotSingh
Copy link
Contributor

@mikepizzo .NET Core 3 is going to GA soon (https://github.com/dotnet/core/blob/master/roadmap.md mentions Sep 2019). Has the work started on this issue?

@mikepizzo mikepizzo modified the milestones: 7.2, 7.3 Sep 17, 2019
@BuairtRi
Copy link

.NET Core 3 went to GA today - do I have to turn off endpoint routing for my OData API to work? What's the update on this?

@dhruvb14
Copy link

Also interested in this as We want to add OData to our API which is .NetCore 3 serving data to our Blazor Client

@itanex
Copy link

itanex commented Oct 23, 2019

I encountered this problem myself. Instead of the workaround proposed above:

// use this 
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// or
services.AddMvc(x => x.EnableEndpointRouting = false)

You can instead decorate each endpoint (controller.action) that you want with the [EnableQuery] attribute. It only takes a few lines of code and things just light up. Now this might not be the ideal solution for most in this post. But is does solve the solution differently without having to sacrifice any version features such as Endpoint Routing.

The video below and my validation is against ASP.NET Core 2.2.0.

Supercharging your Web APIs with OData and ASP.NET Core

@stack111
Copy link

stack111 commented Jan 9, 2020

I encountered this problem myself. Instead of the workaround proposed above:

// use this 
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// or
services.AddMvc(x => x.EnableEndpointRouting = false)

You can instead decorate each endpoint (controller.action) that you want with the [EnableQuery] attribute. It only takes a few lines of code and things just light up. Now this might not be the ideal solution for most in this post. But is does solve the solution differently without having to sacrifice any version features such as Endpoint Routing.

The video below and my validation is against ASP.NET Core 2.2.0.

Supercharging your Web APIs with OData and ASP.NET Core

I confirmed this as a work around with v2.2.

@mikepizzo
Copy link
Member

We added support for .NET Core 3.1 in our 7.3 release, as tracked by Issue #1748. This release allows developers to migrate code from .NET Core 2.x with very little change, but does not support endpoint routing.

Support for endpoint routing is tracked in a new issue #2029.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests