From 994835ce47b994864e0af5486903ec29558db136 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 9 Sep 2016 11:52:57 -0700 Subject: [PATCH] Remove IViewsProvider and make view lookup to the feature provider --- .../ApplicationParts/AssemblyPart.cs | 39 +------- .../ApplicationParts/IViewsProvider.cs | 18 ---- .../Compilation}/ViewInfo.cs | 0 .../Compilation}/ViewInfoContainer.cs | 0 .../Compilation/ViewsFeatureProvider.cs | 49 ++++++++-- .../Compilation/ViewsFeatureProviderTest.cs | 94 ++++++++++++++----- 6 files changed, 111 insertions(+), 89 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/IViewsProvider.cs rename src/{Microsoft.AspNetCore.Mvc.Core/ApplicationParts => Microsoft.AspNetCore.Mvc.Razor/Compilation}/ViewInfo.cs (100%) rename src/{Microsoft.AspNetCore.Mvc.Core/ApplicationParts => Microsoft.AspNetCore.Mvc.Razor/Compilation}/ViewInfoContainer.cs (100%) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/AssemblyPart.cs b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/AssemblyPart.cs index d3b0f0fc8a..a091013710 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/AssemblyPart.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/AssemblyPart.cs @@ -15,24 +15,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts public class AssemblyPart : ApplicationPart, IApplicationPartTypeProvider, - ICompilationReferencesProvider, - IViewsProvider + ICompilationReferencesProvider { - /// - /// Gets the suffix for the view assembly. - /// - public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews"; - - /// - /// Gets the namespace for the type in the view assembly. - /// - public static readonly string ViewInfoContainerNamespace = "AspNetCore"; - - /// - /// Gets the type name for the view collection type in the view assembly. - /// - public static readonly string ViewInfoContainerTypeName = "__PrecompiledViewCollection"; - /// /// Initalizes a new instance. /// @@ -60,27 +44,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts /// public IEnumerable Types => Assembly.DefinedTypes; - /// - public IEnumerable Views - { - get - { - var precompiledAssemblyName = new AssemblyName(Assembly.FullName); - precompiledAssemblyName.Name = precompiledAssemblyName.Name + PrecompiledViewsAssemblySuffix; - - var typeName = $"{ViewInfoContainerNamespace}.{ViewInfoContainerTypeName},{precompiledAssemblyName}"; - var viewInfoContainerTypeName = Type.GetType(typeName); - - if (viewInfoContainerTypeName == null) - { - return null; - } - - var precompiledViews = (ViewInfoContainer)Activator.CreateInstance(viewInfoContainerTypeName); - return precompiledViews.ViewInfos; - } - } - /// public IEnumerable GetReferencePaths() { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/IViewsProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/IViewsProvider.cs deleted file mode 100644 index 862401593e..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/IViewsProvider.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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.Collections.Generic; - -namespace Microsoft.AspNetCore.Mvc.ApplicationParts -{ - /// - /// Exposes a sequence of views associated with an . - /// - public interface IViewsProvider - { - /// - /// Gets the sequence of . - /// - IEnumerable Views { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ViewInfo.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewInfo.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ViewInfo.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewInfo.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ViewInfoContainer.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewInfoContainer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ViewInfoContainer.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewInfoContainer.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs index 360992886d..129df93ec5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs @@ -1,8 +1,10 @@ // 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 System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; namespace Microsoft.AspNetCore.Mvc.Razor.Compilation @@ -12,20 +14,53 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation /// public class ViewsFeatureProvider : IApplicationFeatureProvider { + /// + /// Gets the suffix for the view assembly. + /// + public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews"; + + /// + /// Gets the namespace for the type in the view assembly. + /// + public static readonly string ViewInfoContainerNamespace = "AspNetCore"; + + /// + /// Gets the type name for the view collection type in the view assembly. + /// + public static readonly string ViewInfoContainerTypeName = "__PrecompiledViewCollection"; + /// public void PopulateFeature(IEnumerable parts, ViewsFeature feature) { - foreach (var provider in parts.OfType()) + foreach (var assemblyPart in parts.OfType()) { - var precompiledViews = provider.Views; - if (precompiledViews != null) + var viewInfoContainerTypeName = GetViewInfoContainerType(assemblyPart); + if (viewInfoContainerTypeName == null) { - foreach (var viewInfo in precompiledViews) - { - feature.Views[viewInfo.Path] = viewInfo.Type; - } + continue; + } + + var viewContainer = (ViewInfoContainer)Activator.CreateInstance(viewInfoContainerTypeName); + + foreach (var item in viewContainer.ViewInfos) + { + feature.Views[item.Path] = item.Type; } } } + + /// + /// Gets the type of for the specified . + /// + /// The . + /// The . + protected virtual Type GetViewInfoContainerType(AssemblyPart assemblyPart) + { + var precompiledAssemblyName = new AssemblyName(assemblyPart.Assembly.FullName); + precompiledAssemblyName.Name = precompiledAssemblyName.Name + PrecompiledViewsAssemblySuffix; + + var typeName = $"{ViewInfoContainerNamespace}.{ViewInfoContainerTypeName},{precompiledAssemblyName}"; + return Type.GetType(typeName); + } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs index 77250475e1..081ff63254 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Compilation/ViewsFeatureProviderTest.cs @@ -1,9 +1,11 @@ // 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 System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationParts; -using Moq; using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Compilation @@ -18,49 +20,89 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation applicationPartManager.ApplicationParts.Add( new AssemblyPart(typeof(ViewsFeatureProviderTest).GetTypeInfo().Assembly)); applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider()); - var feature = new MetadataReferenceFeature(); + var feature = new ViewsFeature(); // Act applicationPartManager.PopulateFeature(feature); // Assert - Assert.Empty(feature.MetadataReferences); + Assert.Empty(feature.Views); } [Fact] public void PopulateFeature_ReturnsViewsFromAllAvailableApplicationParts() { // Arrange - var applicationPart1 = new Mock(); - var viewsProvider1 = applicationPart1 - .As() - .SetupGet(p => p.Views) - .Returns(new[] - { - new ViewInfo("/Views/test/Index.cshtml", typeof(object)) - }); - var applicationPart2 = new Mock(); - var viewsProvider2 = applicationPart2 - .As() - .SetupGet(p => p.Views) - .Returns(new[] - { - new ViewInfo("/Areas/Admin/Views/Index.cshtml", typeof(string)), - new ViewInfo("/Areas/Admin/Views/About.cshtml", typeof(int)) - }); - + var part1 = new AssemblyPart(typeof(object).GetTypeInfo().Assembly); + var part2 = new AssemblyPart(GetType().GetTypeInfo().Assembly); + var featureProvider = new TestableViewsFeatureProvider(new Dictionary + { + { part1, typeof(ViewInfoContainer1) }, + { part2, typeof(ViewInfoContainer2) }, + }); var applicationPartManager = new ApplicationPartManager(); - applicationPartManager.ApplicationParts.Add(applicationPart1.Object); - applicationPartManager.ApplicationParts.Add(applicationPart2.Object); - applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider()); - var feature = new MetadataReferenceFeature(); + applicationPartManager.ApplicationParts.Add(part1); + applicationPartManager.ApplicationParts.Add(part2); + applicationPartManager.FeatureProviders.Add(featureProvider); + var feature = new ViewsFeature(); // Act applicationPartManager.PopulateFeature(feature); // Assert - Assert.Empty(feature.MetadataReferences); + Assert.Collection(feature.Views.OrderBy(f => f.Key, StringComparer.Ordinal), + view => + { + Assert.Equal("/Areas/Admin/Views/About.cshtml", view.Key); + Assert.Equal(typeof(int), view.Value); + }, + view => + { + Assert.Equal("/Areas/Admin/Views/Index.cshtml", view.Key); + Assert.Equal(typeof(string), view.Value); + }, + view => + { + Assert.Equal("/Views/test/Index.cshtml", view.Key); + Assert.Equal(typeof(object), view.Value); + }); + } + + private class TestableViewsFeatureProvider : ViewsFeatureProvider + { + private readonly Dictionary _containerLookup; + + public TestableViewsFeatureProvider(Dictionary containerLookup) + { + _containerLookup = containerLookup; + } + + protected override Type GetViewInfoContainerType(AssemblyPart assemblyPart) => + _containerLookup[assemblyPart]; + } + + 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)) + }) + { + } } } }