diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/CompiledViewManfiest.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/CompiledViewManifest.cs similarity index 82% rename from src/Microsoft.AspNetCore.Mvc.Razor/Compilation/CompiledViewManfiest.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Compilation/CompiledViewManifest.cs index b22d462274..42c5c0be7c 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/CompiledViewManfiest.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/CompiledViewManifest.cs @@ -1,7 +1,6 @@ // 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 System.IO; using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; @@ -12,13 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation { public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews"; - public static Type GetManifestType(AssemblyPart assemblyPart, string typeName) - { - var assembly = GetFeatureAssembly(assemblyPart); - return assembly?.GetType(typeName); - } - - private static Assembly GetFeatureAssembly(AssemblyPart assemblyPart) + public static Assembly GetFeatureAssembly(AssemblyPart assemblyPart) { if (assemblyPart.Assembly.IsDynamic || string.IsNullOrEmpty(assemblyPart.Assembly.Location)) { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs index 4253b899f6..89fb227141 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.Extensions.Primitives; @@ -34,20 +35,15 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation { foreach (var assemblyPart in parts.OfType()) { - var viewContainer = GetManifest(assemblyPart); - if (viewContainer == null) + var viewAttributes = GetViewAttributes(assemblyPart); + foreach (var attribute in viewAttributes) { - continue; - } - - foreach (var item in viewContainer.ViewInfos) - { - var relativePath = ViewPath.NormalizePath(item.Path); + var relativePath = ViewPath.NormalizePath(attribute.Path); var viewDescriptor = new CompiledViewDescriptor { ExpirationTokens = Array.Empty(), RelativePath = relativePath, - ViewAttribute = new RazorViewAttribute(relativePath, item.Type), + ViewAttribute = attribute, IsPrecompiled = true, }; @@ -57,19 +53,24 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation } /// - /// Gets the type of for the specified . + /// Gets the sequence of instances associated with the specified . /// /// The . - /// The . - protected virtual ViewInfoContainer GetManifest(AssemblyPart assemblyPart) + /// The sequence of instances. + protected virtual IEnumerable GetViewAttributes(AssemblyPart assemblyPart) { - var type = CompiledViewManfiest.GetManifestType(assemblyPart, FullyQualifiedManifestTypeName); - if (type != null) + if (assemblyPart == null) { - return (ViewInfoContainer)Activator.CreateInstance(type); + throw new ArgumentNullException(nameof(assemblyPart)); } - return null; + var featureAssembly = CompiledViewManfiest.GetFeatureAssembly(assemblyPart); + if (featureAssembly != null) + { + return featureAssembly.GetCustomAttributes(); + } + + return Enumerable.Empty(); } } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs index eb4da99fd7..d37816a53b 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs @@ -6,7 +6,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -188,10 +187,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal } var generatedAssembly = CompileAndEmit(codeDocument, cSharpDocument.GeneratedCode); - var exportedType = generatedAssembly.GetExportedTypes().FirstOrDefault(f => !f.IsNested); + var viewAttribute = generatedAssembly.GetCustomAttribute(); return new CompiledViewDescriptor { - ViewAttribute = new RazorViewAttribute(relativePath, exportedType), + ViewAttribute = viewAttribute, RelativePath = relativePath, }; } diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationParts/CompiledPageFeatureProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationParts/CompiledPageFeatureProvider.cs index e8e72a90c8..389f4b7915 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationParts/CompiledPageFeatureProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationParts/CompiledPageFeatureProvider.cs @@ -1,20 +1,14 @@ // 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 System.Collections.Generic; -using System.Linq; using Microsoft.AspNetCore.Mvc.Razor.Compilation; -using Microsoft.AspNetCore.Mvc.Razor.Internal; -using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; -using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Mvc.ApplicationParts { /// /// An for . /// - public class CompiledPageFeatureProvider : IApplicationFeatureProvider + public class CompiledPageFeatureProvider { /// /// Gets the namespace for the type in the view assembly. @@ -28,47 +22,5 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts private static readonly string FullyQualifiedManifestTypeName = CompiledPageManifestNamespace + "." + CompiledPageManifestTypeName; - - /// - public void PopulateFeature(IEnumerable parts, ViewsFeature feature) - { - foreach (var item in GetCompiledPageDescriptors(parts)) - { - feature.ViewDescriptors.Add(item); - } - } - - /// - /// Gets the sequence of from . - /// - /// The s - /// The sequence of . - public static IEnumerable GetCompiledPageDescriptors(IEnumerable parts) - { - var manifests = parts.OfType() - .Select(part => CompiledViewManfiest.GetManifestType(part, FullyQualifiedManifestTypeName)) - .Where(type => type != null) - .Select(type => (CompiledPageManifest)Activator.CreateInstance(type)); - - foreach (var page in manifests.SelectMany(m => m.CompiledPages)) - { - var normalizedPath = ViewPath.NormalizePath(page.Path); - - var pageAttribute = new RazorPageAttribute( - normalizedPath, - page.CompiledType, - page.RoutePrefix); - - var viewDescriptor = new CompiledViewDescriptor - { - RelativePath = normalizedPath, - ViewAttribute = pageAttribute, - ExpirationTokens = Array.Empty(), - IsPrecompiled = true, - }; - - yield return viewDescriptor; - } - } } } diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs index 93b97cefc9..c72b500a75 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs @@ -28,7 +28,6 @@ namespace Microsoft.Extensions.DependencyInjection builder.AddRazorViewEngine(); - AddFeatureProviders(builder); AddServices(builder.Services); return builder; @@ -50,7 +49,6 @@ namespace Microsoft.Extensions.DependencyInjection builder.AddRazorViewEngine(); - AddFeatureProviders(builder); AddServices(builder.Services); builder.Services.Configure(setupAction); @@ -80,14 +78,6 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } - private static void AddFeatureProviders(IMvcCoreBuilder builder) - { - if (!builder.PartManager.FeatureProviders.OfType().Any()) - { - builder.PartManager.FeatureProviders.Add(new CompiledPageFeatureProvider()); - } - } - // Internal for testing. internal static void AddServices(IServiceCollection services) { diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/CompiledPageApplicationModelProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/CompiledPageApplicationModelProvider.cs index 7684492ebd..1fb3c0bf33 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/CompiledPageApplicationModelProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/CompiledPageApplicationModelProvider.cs @@ -3,9 +3,12 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor.Compilation; +using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Microsoft.Extensions.Options; @@ -58,17 +61,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal } var cachedApplicationModels = new List(); - foreach (var pageDescriptor in GetCompiledPageDescriptors()) + foreach (var pageAttribute in GetRazorPageAttributes(_applicationManager.ApplicationParts)) { - var pageAttribute = (RazorPageAttribute)pageDescriptor.ViewAttribute; - - if (!pageDescriptor.RelativePath.StartsWith(rootDirectory)) + var normalizedPath = ViewPath.NormalizePath(pageAttribute.Path); + if (!normalizedPath.StartsWith(rootDirectory, StringComparison.OrdinalIgnoreCase)) { continue; } - var viewEnginePath = GetViewEnginePath(rootDirectory, pageDescriptor.RelativePath); - var model = new PageApplicationModel(pageDescriptor.RelativePath, viewEnginePath); + var viewEnginePath = GetViewEnginePath(rootDirectory, normalizedPath); + var model = new PageApplicationModel(normalizedPath, viewEnginePath); PageSelectorModel.PopulateDefaults(model, pageAttribute.RouteTemplate); cachedApplicationModels.Add(model); @@ -78,8 +80,33 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal } } - protected virtual IEnumerable GetCompiledPageDescriptors() - => CompiledPageFeatureProvider.GetCompiledPageDescriptors(_applicationManager.ApplicationParts); + /// + /// Gets the sequence of from . + /// + /// The s + /// The sequence of . + protected virtual IEnumerable GetRazorPageAttributes(IEnumerable parts) + { + if (parts == null) + { + throw new ArgumentNullException(nameof(parts)); + } + + return _applicationManager.ApplicationParts + .OfType() + .SelectMany(GetAttributes); + } + + private static IEnumerable GetAttributes(AssemblyPart assemblyPart) + { + var featureAssembly = CompiledViewManfiest.GetFeatureAssembly(assemblyPart); + if (featureAssembly != null) + { + return featureAssembly.GetCustomAttributes(); + } + + return Enumerable.Empty(); + } private string GetViewEnginePath(string rootDirectory, string path) { diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageLoader.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageLoader.cs index b58c000905..3c8cfbad72 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageLoader.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageLoader.cs @@ -28,12 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal { var compileTask = Compiler.CompileAsync(actionDescriptor.RelativePath); var viewDescriptor = compileTask.GetAwaiter().GetResult(); - var viewAttribute = viewDescriptor.ViewAttribute; - - var pageAttribute = new RazorPageAttribute( - viewAttribute.Path, - viewAttribute.ViewType, - routeTemplate: null); + var pageAttribute = (RazorPageAttribute)viewDescriptor.ViewAttribute; return CreateDescriptor(actionDescriptor, pageAttribute); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs index 58aa2023c0..139b9e4fe8 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs @@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal Assert.Equal(FilterScope.Controller, filter2.Scope); var filter3 = descriptor.FilterDescriptors[2]; - Assert.Equal(3, Assert.IsType(filter3.Filter).Value); ; + Assert.Equal(3, Assert.IsType(filter3.Filter).Value); Assert.Equal(FilterScope.Action, filter3.Scope); } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs index aa3086edd7..c61ac53b2b 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs @@ -36,10 +36,23 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation // Arrange var part1 = new AssemblyPart(typeof(object).GetTypeInfo().Assembly); var part2 = new AssemblyPart(GetType().GetTypeInfo().Assembly); - var featureProvider = new TestableViewsFeatureProvider(new Dictionary + var featureProvider = new TestableViewsFeatureProvider(new Dictionary> { - { part1, typeof(ViewInfoContainer1) }, - { part2, typeof(ViewInfoContainer2) }, + { + part1, + new[] + { + new RazorViewAttribute("/Views/test/Index.cshtml", typeof(object)), + } + }, + { + part2, + new[] + { + new RazorViewAttribute("/Areas/Admin/Views/Index.cshtml", typeof(string)), + new RazorViewAttribute("/Areas/Admin/Views/About.cshtml", typeof(int)), + } + }, }); var applicationPartManager = new ApplicationPartManager(); @@ -109,40 +122,16 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation private class TestableViewsFeatureProvider : ViewsFeatureProvider { - private readonly Dictionary _containerLookup; + private readonly Dictionary> _attributeLookup; - public TestableViewsFeatureProvider(Dictionary containerLookup) + public TestableViewsFeatureProvider(Dictionary> attributeLookup) { - _containerLookup = containerLookup; + _attributeLookup = attributeLookup; } - protected override ViewInfoContainer GetManifest(AssemblyPart assemblyPart) - { - var type = _containerLookup[assemblyPart]; - return (ViewInfoContainer)Activator.CreateInstance(type); - } - } - - private class ViewInfoContainer1 : ViewInfoContainer - { - public ViewInfoContainer1() - : base(new[] - { - new ViewInfo("/Views/test/Index.cshtml", typeof(object)) - }) - { - } - } - - private class ViewInfoContainer2 : ViewInfoContainer - { - public ViewInfoContainer2() - : base(new[] - { - new ViewInfo("/Areas/Admin/Views/Index.cshtml", typeof(string)), - new ViewInfo("/Areas/Admin/Views/About.cshtml", typeof(int)) - }) + protected override IEnumerable GetViewAttributes(AssemblyPart assemblyPart) { + return _attributeLookup[assemblyPart]; } } diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageApplicationModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageApplicationModelProviderTest.cs index 3f40cbe5f1..0b291c29a7 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageApplicationModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageApplicationModelProviderTest.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ApplicationParts; -using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Xunit; @@ -19,8 +18,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal // Arrange var descriptors = new[] { - GetDescriptor("/Pages/About.cshtml"), - GetDescriptor("/Pages/Home.cshtml", "some-prefix"), + GetAttribute("/Pages/About.cshtml"), + GetAttribute("/Pages/Home.cshtml", "some-prefix"), }; var provider = new TestCompiledPageApplicationModelProvider(descriptors, new RazorPagesOptions()); var context = new PageApplicationModelProviderContext(); @@ -52,8 +51,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal // Arrange var descriptors = new[] { - GetDescriptor("/Pages/Index.cshtml"), - GetDescriptor("/Pages/Admin/Index.cshtml", "some-template"), + GetAttribute("/Pages/Index.cshtml"), + GetAttribute("/Pages/Admin/Index.cshtml", "some-template"), }; var provider = new TestCompiledPageApplicationModelProvider(descriptors, new RazorPagesOptions { RootDirectory = "/" }); var context = new PageApplicationModelProviderContext(); @@ -87,8 +86,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal // Arrange var descriptors = new[] { - GetDescriptor("/Pages/Index.cshtml"), - GetDescriptor("/Pages/Admin/Index.cshtml", "some-template"), + GetAttribute("/Pages/Index.cshtml"), + GetAttribute("/Pages/Admin/Index.cshtml", "some-template"), }; var provider = new TestCompiledPageApplicationModelProvider(descriptors, new RazorPagesOptions()); var context = new PageApplicationModelProviderContext(); @@ -122,8 +121,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal // Arrange var descriptors = new[] { - GetDescriptor("/Pages/Index.cshtml"), - GetDescriptor("/Pages/Home.cshtml", "/some-prefix"), + GetAttribute("/Pages/Index.cshtml"), + GetAttribute("/Pages/Home.cshtml", "/some-prefix"), }; var provider = new TestCompiledPageApplicationModelProvider(descriptors, new RazorPagesOptions()); var context = new PageApplicationModelProviderContext(); @@ -134,27 +133,19 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal ex.Message); } - private static CompiledViewDescriptor GetDescriptor(string path, string prefix = "") - { - return new CompiledViewDescriptor - { - RelativePath = path, - ViewAttribute = new RazorPageAttribute(path, typeof(object), prefix), - }; - } + private static RazorPageAttribute GetAttribute(string path, string prefix = "") => new RazorPageAttribute(path, typeof(object), prefix); public class TestCompiledPageApplicationModelProvider : CompiledPageApplicationModelProvider { - private readonly IEnumerable _info; + private readonly IEnumerable _attributes; - public TestCompiledPageApplicationModelProvider(IEnumerable info, RazorPagesOptions options) + public TestCompiledPageApplicationModelProvider(IEnumerable attributes, RazorPagesOptions options) : base(new ApplicationPartManager(), new TestOptionsManager(options)) { - _info = info; + _attributes = attributes; } - - protected override IEnumerable GetCompiledPageDescriptors() => _info; + protected override IEnumerable GetRazorPageAttributes(IEnumerable parts) => _attributes; } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs index dfa00e1454..058c0dd19f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs @@ -216,8 +216,7 @@ namespace Microsoft.AspNetCore.Mvc feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), - feature => Assert.IsType(feature), - feature => Assert.IsType(feature)); + feature => Assert.IsType(feature)); } [Fact]