diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageApplicationModelProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageApplicationModelProvider.cs index 5e09d1519a..c2bb7d9a24 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageApplicationModelProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageApplicationModelProvider.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Microsoft.Extensions.Internal; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal { diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs index d6e50480d6..1d5e33c93c 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Microsoft.AspNetCore.Razor.Language; @@ -24,8 +25,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal _pagesOptions = pagesOptionsAccessor.Value; _logger = loggerFactory.CreateLogger(); } - - public int Order => -1000; + + /// + /// Ordered to execute after . + /// + public int Order => -1000 + 10; public void OnProvidersExecuted(PageRouteModelProviderContext context) { @@ -47,6 +51,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal continue; } + if (IsAlreadyRegistered(context, item)) + { + // The CompiledPageRouteModelProvider (or another provider) already registered a PageRoute for this path. + // Don't register a duplicate entry for this route. + continue; + } + var routeModel = new PageRouteModel( relativePath: item.CombinedPath, viewEnginePath: item.FilePathWithoutExtension); @@ -55,5 +66,20 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal context.RouteModels.Add(routeModel); } } + + private bool IsAlreadyRegistered(PageRouteModelProviderContext context, RazorProjectItem projectItem) + { + for (var i = 0; i < context.RouteModels.Count; i++) + { + var routeModel = context.RouteModels[i]; + if (string.Equals(routeModel.ViewEnginePath, projectItem.FilePathWithoutExtension, StringComparison.OrdinalIgnoreCase) && + string.Equals(routeModel.RelativePath, projectItem.CombinedPath, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } } } diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorProjectPageRouteModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorProjectPageRouteModelProviderTest.cs index 95fea9b11f..f9c53f1db1 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorProjectPageRouteModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorProjectPageRouteModelProviderTest.cs @@ -176,5 +176,40 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal Assert.Equal("/Pages/Index.cshtml", model.RelativePath); }); } + + [Fact] + public void OnProvidersExecuting_DoesNotAddPageDirectivesIfItAlreadyExists() + { + // Arrange + var fileProvider = new TestFileProvider(); + var file1 = fileProvider.AddFile("/Pages/Home.cshtml", "@page"); + var file2 = fileProvider.AddFile("/Pages/Test.cshtml", "@page"); + + var dir1 = fileProvider.AddDirectoryContent("/Pages", new IFileInfo[] { file1, file2 }); + fileProvider.AddDirectoryContent("/", new[] { dir1 }); + + var project = new TestRazorProject(fileProvider); + + var optionsManager = new TestOptionsManager(); + optionsManager.Value.RootDirectory = "/"; + var provider = new RazorProjectPageRouteModelProvider(project, optionsManager, NullLoggerFactory.Instance); + var context = new PageRouteModelProviderContext(); + var pageModel = new PageRouteModel("/Pages/Test.cshtml", "/Pages/Test"); + context.RouteModels.Add(pageModel); + + // Act + provider.OnProvidersExecuting(context); + + // Assert + Assert.Collection(context.RouteModels, + model => Assert.Same(pageModel, model), + model => + { + Assert.Equal("/Pages/Home.cshtml", model.RelativePath); + Assert.Equal("/Pages/Home", model.ViewEnginePath); + Assert.Collection(model.Selectors, + selector => Assert.Equal("Pages/Home", selector.AttributeRouteModel.Template)); + }); + } } }