-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
tldr; for developers with custom IRouter implementations:
- IRouter is currently not compatible with endpoint routing.
- We will attempt to improve this in 3.0, with new APIs, documentation, or both
- If you are using a custom IRouter implementation in 2.2 we recommend disabling endpoint routing:
services.AddMvc(options => options.EnableEndpointRouting = false)
Summary
I'm developing a plan to make it possible for folks implementing IRouter based functionality to migrate endpoint routing. This is our future direction for MVC and the stack in general, and we don't want to leave users/frameworks behind.
I'm also lumping in this category custom IActionSelector implementations. IActionSelector is not used in endpoint routing so it's just as relevant/obsolete for new apps.
Over time we're going to evolve in the direction of endpoint routing being the primary experience for the whole stack. I don't expect that we'd ever be able to delete IRouter or remove IRouter support from MVC. We can offer users more options to migrate and try to make it as enticing as possible, but some portion will be left behind; either by our choice not to add a feature they want, or their choice not to adopt new features and concepts.
Analysis
Based on analysis, I've found 3 major types of usages:
- I want to rewrite the route values (usually localization) - example
- My route values are in a database (usually a CMS, SimpleCommerce) - example
- I am implementing a framework (OData) - example
Note that these are roughly in ascending order of 'off-road-ness' - reusing less of our implementation gradually. Most genuine challenges in framework design related to application authors writing extensibility that uses and is used by the framework.
Let's go case by case and look at these...
I want to rewrite the route values
Usually the case for this is that you want to have one set of actions that you 'multiply' (cross-product) across different localized strings that you want to appear in the URL. There's a major pivot here regarding whether you want to localize the 'route values' or just localize the URL template.
In general all of these things 'just work' with application model today. Some users choose to implement this with IRouter because they have done that in the past or it's what seems most obvious to them, but there's no real problem with using application model for this.
My route values in the database
Generally this kind of system works by defining a slug route in the route table that matches all URLs, and then looking up a set of route values in a database using the URL path or part of it as a key.
Example:
var urlSlug = ... do database query...;
RouteData.Values["controller"] = urlSlug.EntityType.RoutingController;
RouteData.Values["action"] = urlSlug.EntityType.RoutingAction;
RouteData.Values["id"] = urlSlug.EntityId;
This requires a slightly more involved solution, because the route templates can't be defined statically, and because we don't provide a simple way to 'run code' to select an MVC action. My assumption here is that this user doesn't want to access the DB once on startup to create the route table, they want to make configuration changes while the app is running.
The key here is that this user is reusing MVC's action selector by rewriting the route values.
Here's a proposal:
- Make it so that an
IEndpointSelectorPolicycan be filter where it applies by candidate set. This is for isolation. - Register a single endpoint that with a metadata that identifies it as a 'slug' endpoint
- Write an endpoint selector policy that selects the real/action/endpoint and returns it when it finds the 'slug' endpoint
This has a few drawbacks:
- There is no path to support link generation, but I have yet to see an example of this pattern that includes link generation.
- This does not allow you to reuse HTTP method filtering or other policies. The custom implementation is responsible for handling these concerns.
Another approach would be to rewrite the URL. That might be more straightforward.
I am implementing a framework
Upon further analysis, this case is very similar to the above. The framework registers a route that matches a 'slug', and has a custom implementation that produces an action.
This case has fewer drawbacks because they are not using MVC's action selection.
Next steps
Make it so that an
IEndpointSelectorPolicycan be filter where it applies by candidate set. This is for isolation.
We need to do this. This is a nice perf enhancement to IEndpointSelectorPolicy and can unblock a framework like OData migrate. We need to do this in 2.2 so it's not a breaking change.
We should consider further whether URL rewriting is a better solution for most of these scenarios.
I think the timeframe for any other choices we'd consider is 3.0