diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactory.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactory.cs index 07780cd096..4f53acfef5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterFactory.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.AspNetCore.Mvc.Filters; namespace Microsoft.AspNetCore.Mvc.Internal @@ -26,9 +27,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal var actionDescriptor = actionContext.ActionDescriptor; var staticFilterItems = new FilterItem[actionDescriptor.FilterDescriptors.Count]; - for (var i = 0; i < actionDescriptor.FilterDescriptors.Count; i++) + + var orderedFilters = actionDescriptor.FilterDescriptors + .OrderBy( + filter => filter, + FilterDescriptorOrderComparer.Comparer) + .ToList(); + + for (var i = 0; i < orderedFilters.Count; i++) { - staticFilterItems[i] = new FilterItem(actionDescriptor.FilterDescriptors[i]); + staticFilterItems[i] = new FilterItem(orderedFilters[i]); } var allFilterItems = new List(staticFilterItems); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/FilterFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/FilterFactoryTest.cs index e39f5c4c96..d382bd386e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/FilterFactoryTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/FilterFactoryTest.cs @@ -89,6 +89,62 @@ namespace Microsoft.AspNetCore.Mvc.Internal f => Assert.Same(staticFilter2, f)); } + [Fact] + public void GetAllFilters_OrdersFilters() + { + // Arrange + var filter1 = new TestOrderedFilter { Order = 1000 }; + var filter2 = new TestFilter(); + var filter3 = new TestOrderedFilter { Order = 10 }; + var actionContext = CreateActionContext(new[] + { + new FilterDescriptor(filter1, FilterScope.Action), + new FilterDescriptor(filter2, FilterScope.Action), + new FilterDescriptor(filter3, FilterScope.Action), + }); + var filterProviders = new[] { new DefaultFilterProvider() }; + + // Act + var filterResult = FilterFactory.GetAllFilters(filterProviders, actionContext); + + // Assert + Assert.Collection( + filterResult.Filters, + f => Assert.Same(filter2, f), + f => Assert.Same(filter3, f), + f => Assert.Same(filter1, f)); + } + + [Fact] + public void GetAllFilters_CachesFilterOrder() + { + // Arrange + var filter1 = new TestOrderedFilter { Order = 1000 }; + var filter2 = new TestFilter(); + var filter3 = new TestOrderedFilter { Order = 10 }; + var actionContext = CreateActionContext(new[] + { + new FilterDescriptor(filter1, FilterScope.Action), + new FilterDescriptor(filter2, FilterScope.Action), + new FilterDescriptor(filter3, FilterScope.Action), + }); + var filterProviders = new[] { new DefaultFilterProvider() }; + + // Act + var filterResult = FilterFactory.GetAllFilters(filterProviders, actionContext); + var requestFilters = FilterFactory.CreateUncachedFilters( + filterProviders, + actionContext, + filterResult.CacheableFilters); + + // Assert + Assert.Collection( + requestFilters, + f => Assert.Same(filter2, f), + f => Assert.Same(filter3, f), + f => Assert.Same(filter1, f)); + } + [Fact] public void GetAllFilters_CachesFilterFromFactory() { @@ -266,6 +322,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal } } + private class TestOrderedFilter : IFilterMetadata, IOrderedFilter + { + public int Order { get; set; } + } + private static ActionContext CreateActionContext(FilterDescriptor[] filterDescriptors) { var actionDescriptor = new ActionDescriptor diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs index 4dc5ed4a40..6b0bbd55dd 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs @@ -1074,6 +1074,17 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP Assert.Equal("/Login?ReturnUrl=%2FModelWithAuthFilter", response.Headers.Location.PathAndQuery); } + [Fact] + public async Task AuthorizeAttributeIsExecutedPriorToAutoAntiforgeryFilter() + { + // Act + var response = await Client.PostAsync("/Pages/Admin/Edit", new StringContent("")); + + // Assert + Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); + Assert.Equal("/Login?ReturnUrl=%2FPages%2FAdmin%2FEdit", response.Headers.Location.PathAndQuery); + } + [Fact] public async Task PageFiltersAppliedToPageModel_AreExecuted() { diff --git a/test/WebSites/RazorPagesWebSite/Pages/Admin/Edit.cshtml b/test/WebSites/RazorPagesWebSite/Pages/Admin/Edit.cshtml new file mode 100644 index 0000000000..a7b9c2c62e --- /dev/null +++ b/test/WebSites/RazorPagesWebSite/Pages/Admin/Edit.cshtml @@ -0,0 +1,11 @@ +@page +@functions +{ + public void OnPost() + { + } +} + +
+ +