public async Task AttributeRoute_UsesUpdatedActionDescriptors()
        {
            // Arrange
            var handler = new Mock<IRouter>(MockBehavior.Strict);
            handler
                .Setup(h => h.RouteAsync(It.IsAny<RouteContext>()))
                .Callback<RouteContext>(c => c.Handler = NullHandler)
                .Returns(Task.FromResult(true))
                .Verifiable();

            var actionDescriptors = new List<ActionDescriptor>()
            {
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Blog/{id}"
                    },
                    RouteConstraints = new List<RouteDataActionConstraint>()
                    {
                        new RouteDataActionConstraint(TreeRouter.RouteGroupKey, "1"),
                    },
                },
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Store/Buy/{id}"
                    },
                    RouteConstraints = new List<RouteDataActionConstraint>()
                    {
                        new RouteDataActionConstraint(TreeRouter.RouteGroupKey, "2"),
                    },
                },
            };

            var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>(MockBehavior.Strict);
            actionDescriptorProvider
                .SetupGet(ad => ad.ActionDescriptors)
                .Returns(new ActionDescriptorCollection(actionDescriptors, version: 1));

            var policy = new UriBuilderContextPooledObjectPolicy(new UrlTestEncoder());
            var pool = new DefaultObjectPool<UriBuildingContext>(policy);

            var route = new AttributeRoute(
                handler.Object,
                actionDescriptorProvider.Object,
                Mock.Of<IInlineConstraintResolver>(),
                pool,
                new UrlTestEncoder(),
                NullLoggerFactory.Instance);

            var requestServices = new Mock<IServiceProvider>(MockBehavior.Strict);
            requestServices
                .Setup(s => s.GetService(typeof(ILoggerFactory)))
                .Returns(NullLoggerFactory.Instance);

            var httpContext = new DefaultHttpContext();
            httpContext.Request.Path = new PathString("/api/Store/Buy/5");
            httpContext.RequestServices = requestServices.Object;

            var context = new RouteContext(httpContext);

            // Act 1
            await route.RouteAsync(context);

            // Assert 1
            Assert.NotNull(context.Handler);
            Assert.Equal("5", context.RouteData.Values["id"]);
            Assert.Equal("2", context.RouteData.Values[TreeRouter.RouteGroupKey]);

            handler.Verify(h => h.RouteAsync(It.IsAny<RouteContext>()), Times.Once());

            // Arrange 2 - remove the action and update the collection
            actionDescriptors.RemoveAt(1);
            actionDescriptorProvider
                .SetupGet(ad => ad.ActionDescriptors)
                .Returns(new ActionDescriptorCollection(actionDescriptors, version: 2));

            context = new RouteContext(httpContext);

            // Act 2
            await route.RouteAsync(context);

            // Assert 2
            Assert.Null(context.Handler);
            Assert.Empty(context.RouteData.Values);

            handler.Verify(h => h.RouteAsync(It.IsAny<RouteContext>()), Times.Once());
        }
        public async Task AttributeRoute_UsesUpdatedActionDescriptors()
        {
            // Arrange
            var handler = new Mock <IRouter>(MockBehavior.Strict);

            handler
            .Setup(h => h.RouteAsync(It.IsAny <RouteContext>()))
            .Callback <RouteContext>(c => c.IsHandled = true)
            .Returns(Task.FromResult(true))
            .Verifiable();

            var actionDescriptors = new List <ActionDescriptor>()
            {
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Blog/{id}"
                    },
                    RouteConstraints = new List <RouteDataActionConstraint>()
                    {
                        new RouteDataActionConstraint(AttributeRouting.RouteGroupKey, "1"),
                    },
                },
                new ActionDescriptor()
                {
                    AttributeRouteInfo = new AttributeRouteInfo()
                    {
                        Template = "api/Store/Buy/{id}"
                    },
                    RouteConstraints = new List <RouteDataActionConstraint>()
                    {
                        new RouteDataActionConstraint(AttributeRouting.RouteGroupKey, "2"),
                    },
                },
            };

            var actionDescriptorsProvider = new Mock <IActionDescriptorsCollectionProvider>(MockBehavior.Strict);

            actionDescriptorsProvider
            .SetupGet(ad => ad.ActionDescriptors)
            .Returns(new ActionDescriptorsCollection(actionDescriptors, version: 1));

            var route = new AttributeRoute(
                handler.Object,
                actionDescriptorsProvider.Object,
                Mock.Of <IInlineConstraintResolver>(),
                NullLoggerFactory.Instance);

            var requestServices = new Mock <IServiceProvider>(MockBehavior.Strict);

            requestServices
            .Setup(s => s.GetService(typeof(ILoggerFactory)))
            .Returns(NullLoggerFactory.Instance);

            var httpContext = new DefaultHttpContext();

            httpContext.Request.Path    = new PathString("/api/Store/Buy/5");
            httpContext.RequestServices = requestServices.Object;

            var context = new RouteContext(httpContext);

            // Act 1
            await route.RouteAsync(context);

            // Assert 1
            Assert.True(context.IsHandled);
            Assert.Equal("5", context.RouteData.Values["id"]);
            Assert.Equal("2", context.RouteData.Values[AttributeRouting.RouteGroupKey]);

            handler.Verify(h => h.RouteAsync(It.IsAny <RouteContext>()), Times.Once());

            // Arrange 2 - remove the action and update the collection
            actionDescriptors.RemoveAt(1);
            actionDescriptorsProvider
            .SetupGet(ad => ad.ActionDescriptors)
            .Returns(new ActionDescriptorsCollection(actionDescriptors, version: 2));

            context = new RouteContext(httpContext);

            // Act 2
            await route.RouteAsync(context);

            // Assert 2
            Assert.False(context.IsHandled);
            Assert.Empty(context.RouteData.Values);

            handler.Verify(h => h.RouteAsync(It.IsAny <RouteContext>()), Times.Once());
        }