Example #1
0
        public void Create_CreatesCandidateSet(int count)
        {
            // Arrange
            var endpoints = new RouteEndpoint[count];

            for (var i = 0; i < endpoints.Length; i++)
            {
                endpoints[i] = CreateEndpoint($"/{i}");
            }

            var builder    = CreateDfaMatcherBuilder();
            var candidates = builder.CreateCandidates(endpoints);

            // Act
            var candidateSet = new CandidateSet(candidates);

            // Assert
            for (var i = 0; i < candidateSet.Count; i++)
            {
                ref var state = ref candidateSet[i];
                Assert.True(candidateSet.IsValidCandidate(i));
                Assert.Same(endpoints[i], state.Endpoint);
                Assert.Equal(candidates[i].Score, state.Score);
                Assert.Null(state.Values);

                candidateSet.SetValidity(i, false);
                Assert.False(candidateSet.IsValidCandidate(i));
            }
        public override Task SelectAsync(
            ProtoContext httpContext,
            EndpointSelectorContext context,
            CandidateSet candidateSet)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (candidateSet == null)
            {
                throw new ArgumentNullException(nameof(candidateSet));
            }

            // Fast path: We can specialize for trivial numbers of candidates since there can
            // be no ambiguities
            switch (candidateSet.Count)
            {
            case 0:
            {
                // Do nothing
                break;
            }

            case 1:
            {
                if (candidateSet.IsValidCandidate(0))
                {
                    ref var state = ref candidateSet[0];
                    context.Endpoint    = state.Endpoint;
                    context.RouteValues = state.Values;
                }

                break;
            }
 public Task ApplyAsync(ProtoContext httpContext, EndpointSelectorContext context, CandidateSet candidates)
 {
     throw new NotImplementedException();
 }
Example #4
0
        public sealed override Task MatchAsync(ProtoContext httpContext, EndpointSelectorContext context)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // All of the logging we do here is at level debug, so we can get away with doing a single check.
            var log = _logger.IsEnabled(LogLevel.Debug);

            // The sequence of actions we take is optimized to avoid doing expensive work
            // like creating substrings, creating route value dictionaries, and calling
            // into policies like versioning.
            var path = httpContext.Request.Path.Value;

            // First tokenize the path into series of segments.
            Span <PathSegment> buffer = stackalloc PathSegment[_maxSegmentCount];
            var count    = FastPathTokenizer.Tokenize(path, buffer);
            var segments = buffer.Slice(0, count);

            // FindCandidateSet will process the DFA and return a candidate set. This does
            // some preliminary matching of the URL (mostly the literal segments).
            var(candidates, policies) = FindCandidateSet(httpContext, path, segments);
            if (candidates.Length == 0)
            {
                if (log)
                {
                    Logger.CandidatesNotFound(_logger, path);
                }

                return(Task.CompletedTask);
            }

            if (log)
            {
                Logger.CandidatesFound(_logger, path, candidates);
            }

            // At this point we have a candidate set, defined as a list of endpoints in
            // priority order.
            //
            // We don't yet know that any candidate can be considered a match, because
            // we haven't processed things like route constraints and complex segments.
            //
            // Now we'll iterate each endpoint to capture route values, process constraints,
            // and process complex segments.

            // `candidates` has all of our internal state that we use to process the
            // set of endpoints before we call the EndpointSelector.
            //
            // `candidateSet` is the mutable state that we pass to the EndpointSelector.
            var candidateSet = new CandidateSet(candidates);

            for (var i = 0; i < candidates.Length; i++)
            {
                // PERF: using ref here to avoid copying around big structs.
                //
                // Reminder!
                // candidate: readonly data about the endpoint and how to match
                // state: mutable storarge for our processing
                ref var candidate = ref candidates[i];
                ref var state     = ref candidateSet[i];
Example #5
0
 /// <summary>
 /// Asynchronously selects an <see cref="Endpoint"/> from the <see cref="CandidateSet"/>.
 /// </summary>
 /// <param name="httpContext">The <see cref="ProtoContext"/> associated with the current request.</param>
 /// <param name="context">The <see cref="EndpointSelectorContext"/> associated with the current request.</param>
 /// <param name="candidates">The <see cref="CandidateSet"/>.</param>
 /// <returns>A <see cref="Task"/> that completes asynchronously once endpoint selection is complete.</returns>
 /// <remarks>
 /// An <see cref="EndpointSelector"/> should assign the <see cref="EndpointSelectorContext.Endpoint"/>
 /// and <see cref="EndpointSelectorContext.RouteValues"/> properties once an endpoint is selected.
 /// </remarks>
 public abstract Task SelectAsync(
     ProtoContext httpContext,
     EndpointSelectorContext context,
     CandidateSet candidates);