public async Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

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

            var hasCandidates = false;
            var valid         = true;

            for (int index = 0; index < candidates.Count; index++)
            {
                var endpoint = candidates[index].Endpoint;

                var allMetadata = endpoint?.Metadata
                                  .GetOrderedMetadata <IFeatureFilterMetadata>();

                if (allMetadata != null && allMetadata.Any())
                {
                    foreach (var metadata in allMetadata)
                    {
                        var featureService = httpContext
                                             .RequestServices
                                             .GetService <IFeatureService>();

                        _diagnostics.FeatureMatcherPolicyEvaluatingFeatures(endpoint.DisplayName, metadata.Name);

                        if (!String.IsNullOrWhiteSpace(metadata.Name))
                        {
                            if (!await featureService.IsEnabledAsync(metadata.Name.Trim()))
                            {
                                _diagnostics.FeatureMatcherPolicyEndpointIsNotValid(endpoint.DisplayName);

                                valid = false & valid;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    _diagnostics.FeatureMatcherPolicyEndpointIsValid(endpoint.DisplayName);
                    valid = true;
                }

                hasCandidates |= valid;
                candidates.SetValidity(index, value: valid);
            }

            if (!hasCandidates)
            {
                var fallbackService = httpContext
                                      .RequestServices
                                      .GetService <EndpointFallbackService>();

                if (fallbackService != null)
                {
                    var requestPath = httpContext.Request.Path;

                    _diagnostics.FeatureMatcherPolicyExecutingFallbackEndpoint(requestPath);

                    var defaultEndPoint = fallbackService.CreateFallbackEndpoint(requestPath);

                    httpContext.SetEndpoint(defaultEndPoint);
                    httpContext.Request.RouteValues = null;
                }
            }
        }
        public async Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

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

            var hasCandidates = false;
            var valid         = true;

            for (int index = 0; index < candidates.Count; index++)
            {
                var endpoint = candidates[index].Endpoint;

                var allMetadata = endpoint?.Metadata
                                  .GetOrderedMetadata <IFeatureFilterMetadata>();

                if (allMetadata != null && allMetadata.Any())
                {
                    foreach (var metadata in allMetadata)
                    {
                        _diagnostics.FeatureMatcherPolicyEvaluatingFeatures(endpoint.DisplayName, metadata.Names, metadata.ProductName);

                        var featureService = httpContext
                                             .RequestServices
                                             .GetService <IFeatureService>();

                        var tokenizer = new StringTokenizer(metadata.Names, split_characters);

                        foreach (var token in tokenizer)
                        {
                            var featureName = token.Trim();

                            if (featureName.HasValue && featureName.Length > 0)
                            {
                                if (!await featureService.IsEnabledAsync(featureName.Value, metadata.ProductName))
                                {
                                    _diagnostics.FeatureMatcherPolicyEndpointIsNotValid(endpoint.DisplayName);

                                    valid = false & valid;
                                    break;
                                }
                            }
                        }
                    }
                }
                else
                {
                    _diagnostics.FeatureMatcherPolicyEndpointIsValid(endpoint.DisplayName);

                    valid = true;
                }

                hasCandidates |= valid;
                candidates.SetValidity(index, value: valid);
            }

            if (!hasCandidates)
            {
                var fallbackService = httpContext
                                      .RequestServices
                                      .GetService <EndpointFallbackService>();

                if (fallbackService != null)
                {
                    _diagnostics.FeatureMatcherPolicyExecutingFallbackEndpoint(httpContext.Request.Path);

                    httpContext.SetEndpoint(
                        CreateFallbackEndpoint(fallbackService.RequestDelegate, fallbackService.EndpointDisplayName));

                    httpContext.Request.RouteValues = null;
                }
            }
        }