This changes TemplateMatcher to mutate RouteData.Values directly instead
of creating a new dictionary and then merging in values. This is one the
biggest single costs in routing in terms of both allocations and execution
time.
So Match now becomes TryMatch. This will dirty the state of the RVD, so
the caller needs to snapshot it before calling into it (handled
inside the TreeRouter or RouteCollection).
Some subtle changes were needed to how/when values are added to be
compatible with the existing tests. The general idea is that we add null
values for non-parameter defaults or catchalls, but only if they don't
trounce an existing value. This logic used to live in MergeValues but now
it's in TryMatch since TryMatch might be working from existing data.
Also fixed the .sln to avoid building a package that we use as shared
source.
- aspnet/Coherence-Signed#187
- remove `<RootNamespace>` settings but maintain other unique aspects e.g. `<DnxInvisibleContent ... />`
- in a few cases, standardize on VS version `14.0` and not something more specific
Replaces a bunch of dictionary operations with indexing into an array by
doing some caching. Also eliminating an enumerator allocation by changing
from IReadOnlyDictionary to RouteValueDictionary.
This is consistent with other constraint types in routing, and avoids a
naming conflict with MVC.
This is a change **away** from the names used in System.Web and
System.Web.Http.Routing, but it seems worth doing for consistency and
clarity.
Constraint code ported from WebAPI2. Tests are new.
Also a bunch of misc cleanup for constraints.
- Move IRouteConstraint to abstractions
- Fix namespace of a constraint
- Some general style cleanup
- use RouteValueDictionary in the public API
Adds IRouterHandler, an abstraction for endpoints in the routing system
that can't chain (example: delegates). The idea is that some kinds of
routes aren't really friendly to chaining. If you don't support chaining,
then accept IRouteHandler and work with that rather than IRouter.
There's one implementation of IRouteHandler, RouteHandler. It implements
both IRouter and IRouteHandler.
Adds RouteBase as a base class for routes based on our template syntax and
defaults/constraints/data-tokens. Updated a lot of signatures to be
get/set virtual and mutable to facilitate or bigger variety of usage
scenarios.
Renamed TemplateRoute to just Route, now inherits from RouteBase.
Adds IRoutingFeature for middleware scenarios where you don't have access
to the route context.
Also adds some basic extension methods for accessing route values.
This change optimizes allocations by RouteValueDictionary based on usage.
First, implement a struct Enumerator, and expose the concrete RVD type
from all extensibility points. We wanted to try and decouple this code
from RVD originally and use IDictionary everywhere. After doing that we've
found that it allocates an unacceptable number of enumerators.
Secondly, optimize copies of RVD for the case where you're copying an RVC
to another (common case). When doing this we can copy the count to get the
right capacity, and copy the entries without allocating an enumerator.
Lastly, optimize RVD for the case where it's a wrapper around a poco
object. We 'upgrade' to a writable full dictionary if you try to write to
it, or call one of a number of APIs that are uncommonly used. We could
produce optimized versions of things like `Keys` and `CopyTo` if necessary
in the future.
This change removes the call to string.Split and a few substrings, and
replaces it with a tokenizer API. The tokenizer isn't really optimized
right now for compute - it should probably be an iterator- but it's a
significant improvement on what we're doing.
- Removed existing logger scopes as we want to minimize the number of scopes being created.
- Cleaned up tests related to removal of scopes.
- Added new log statements.
- Removed old logger structure base implementation and related tests. Added new tests also.
the errors that can happen in one message. I have separated the message in 2 different messages.
1. When there is a parameter or a literal following the optional parameter.
2. when optional parameter is preceded by a literal other than period which is not allowed.
This change adds a feature needed for aspnet/Mvc#302
There's a new option in routing that allows link-generation to proceed
when the route values cannot be validated. The key scenario for this is
during development of an MVC site. Routing will refuse to generate a link
to actions which don't exists, this is a breaking change from the MVC5
behavior. Setting UseBestEffortLinkGeneration will allow routing to return
a value even when we can't match the action.
This option will remain off by default - setting this to on will impact
link-generation in a bunch of scenarios involving areas where we've
improved the logic for MVC6. If you're considering leaving this on outside
of development scenarios, then make sure to be as explicit with route values
as possible (don't rely on ambient values).
Functional tests to follow up in the MVC repo.
- `DefaultInlineConstraintResolver` has no need of a `IServiceProvider`
nits:
- add doc comments for changed `DefaultInlineConstraintResolver` ctor
- let VS add a dev server port to sample's .kproj
- add debugSettings.json and .vs/ to .gitignore
1. Template parser now allows a parameter to be an optional parameter in a complex segment if
it is the last and only optional parameter and it is followed by a period.
2. Template matcher modified to take into consideration the optional parameter in the complex
segment. Also the period shouldn't be present if the optional parameter is not present
Added OptionalRouteConstraint class to take care of optional inline parameter. It will create the OptionalRouteConstraint for a inline parameter that is optional with real constraint on the parameter as inner constraint of OptionalRouteConstraint.
The properties on TemplateRoute for DataTokens and Defaults are now
readonly. This prevents modifying these collections in a way that
invalidates cached data, or violates thread-safety.
To do the same for constraints, this change includes a substantial refactor
of how we realize inline constraints, and moves the constraint resolver
out of the parsing phase.
This allow creates a builder for the constraint map, that will make it
easier to implement features like optional constraints, and is reusable
for anyone building their own type of routing system.
This is the routing part of the fix. MVC will be updated as well
(attribute routing).
As the graph of routers is traversed, routers add themselves to the
current 'path', which unwinds on a failed path.
This mechanism is opt-in. Whoever adds something needs to remove it as
part of cleanup. If a router in the tree doesn't interact with the
.Routers property, then there are no consequences for those that do.
Additionally, fixing #116 as part of the same change. This means that we
create a nested 'RouteData' and then restore it on the way out. This is
simpler than just dealing with the .Routers property in isolation.
Changed the implementation of route template to merge the existing route data
with the values obtained from parsing the request path with the given template.
Restored original route data values in case the route template data does not match.
This change makes RouteValueDictionary a full IDictionary implementation
instead of a subclass of Dictionary.
Followed the patterns used in the old implementation, namely preserving
the struct-returning behavior of Keys/Values/GetEnumerator.
This is useful for a variety of interesting scenarios in link generation
where a default value doesn't appear in the route template as a parameter.
This can be used to implement the desired behavior for areas - where the
'area' key is sticky.
This change adds tests and makes the behavior consistent with legacy MVC
as far as what values are visible in constraints.
This is important because it allows constraints to make decisions based on
whether or not a value is present even if it's not in the template. This
is similar to the behavior of WebAPI link generation or Area link
generation in MVC 5 - but without hardcoding.
This is the routing part of these changes, and just the breaking changes
parts.
Follow-ups will add:
- DataTokens
- Tracking the logical stack of routers
Moving out Default Handler and IInlineConstraintResolver from RouteCollection.
These are moved to a new interface IRouteBuilder, (instead of an IInlineConstraintResolver, it takes in an IServiceProvider).
This means all RouteCollectionExtensions are moved to RouteBuilderExtensions.
For link generation to areas, we need to provide the set of values that
the route could potentially provide.
Basically if we know what action we want to reach, we want to know whether
or not a given route could hit that action before giving it the OK to
generate a link.
For instance a route like '{controller}' couldn't hit an action like
'HomeController:DoACoolThing', since it can never provide a value for
'action'. This makes it possible for WebFX to make the right decision
without changing the behavior of any of the routing constructs. This also
has the side-effect of removing a class of order dependencies in routing
that cause bad links to be generated.
We'll need to access the accepted values to do proper link generation, so
separating this process out into 2 parts.
Also moving defaults into the TemplateBinder because they are conceptually
part of the route, not part of the request. I'll do the same for
TemplateMatcher soon, but it's a big change and worth separating.