Remove IViewsProvider and make view lookup to the feature provider
This commit is contained in:
parent
809d2bf7ec
commit
994835ce47
|
|
@ -15,24 +15,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
public class AssemblyPart :
|
public class AssemblyPart :
|
||||||
ApplicationPart,
|
ApplicationPart,
|
||||||
IApplicationPartTypeProvider,
|
IApplicationPartTypeProvider,
|
||||||
ICompilationReferencesProvider,
|
ICompilationReferencesProvider
|
||||||
IViewsProvider
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets the suffix for the view assembly.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the namespace for the <see cref="ViewInfoContainer"/> type in the view assembly.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly string ViewInfoContainerNamespace = "AspNetCore";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type name for the view collection type in the view assembly.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly string ViewInfoContainerTypeName = "__PrecompiledViewCollection";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initalizes a new <see cref="AssemblyPart"/> instance.
|
/// Initalizes a new <see cref="AssemblyPart"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -60,27 +44,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerable<TypeInfo> Types => Assembly.DefinedTypes;
|
public IEnumerable<TypeInfo> Types => Assembly.DefinedTypes;
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<ViewInfo> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerable<string> GetReferencePaths()
|
public IEnumerable<string> GetReferencePaths()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Exposes a sequence of views associated with an <see cref="ApplicationPart"/> .
|
|
||||||
/// </summary>
|
|
||||||
public interface IViewsProvider
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the sequence of <see cref="ViewInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
IEnumerable<ViewInfo> Views { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||||
|
|
@ -12,20 +14,53 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ViewsFeatureProvider : IApplicationFeatureProvider<ViewsFeature>
|
public class ViewsFeatureProvider : IApplicationFeatureProvider<ViewsFeature>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the suffix for the view assembly.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the namespace for the <see cref="ViewInfoContainer"/> type in the view assembly.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string ViewInfoContainerNamespace = "AspNetCore";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type name for the view collection type in the view assembly.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string ViewInfoContainerTypeName = "__PrecompiledViewCollection";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ViewsFeature feature)
|
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ViewsFeature feature)
|
||||||
{
|
{
|
||||||
foreach (var provider in parts.OfType<IViewsProvider>())
|
foreach (var assemblyPart in parts.OfType<AssemblyPart>())
|
||||||
{
|
{
|
||||||
var precompiledViews = provider.Views;
|
var viewInfoContainerTypeName = GetViewInfoContainerType(assemblyPart);
|
||||||
if (precompiledViews != null)
|
if (viewInfoContainerTypeName == null)
|
||||||
{
|
{
|
||||||
foreach (var viewInfo in precompiledViews)
|
continue;
|
||||||
{
|
}
|
||||||
feature.Views[viewInfo.Path] = viewInfo.Type;
|
|
||||||
}
|
var viewContainer = (ViewInfoContainer)Activator.CreateInstance(viewInfoContainerTypeName);
|
||||||
|
|
||||||
|
foreach (var item in viewContainer.ViewInfos)
|
||||||
|
{
|
||||||
|
feature.Views[item.Path] = item.Type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of <see cref="ViewInfoContainer"/> for the specified <paramref name="assemblyPart"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assemblyPart">The <see cref="AssemblyPart"/>.</param>
|
||||||
|
/// <returns>The <see cref="ViewInfoContainer"/> <see cref="Type"/>.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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 System.Reflection;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||||
using Moq;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||||
|
|
@ -18,49 +20,89 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||||
applicationPartManager.ApplicationParts.Add(
|
applicationPartManager.ApplicationParts.Add(
|
||||||
new AssemblyPart(typeof(ViewsFeatureProviderTest).GetTypeInfo().Assembly));
|
new AssemblyPart(typeof(ViewsFeatureProviderTest).GetTypeInfo().Assembly));
|
||||||
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
|
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
|
||||||
var feature = new MetadataReferenceFeature();
|
var feature = new ViewsFeature();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
applicationPartManager.PopulateFeature(feature);
|
applicationPartManager.PopulateFeature(feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(feature.MetadataReferences);
|
Assert.Empty(feature.Views);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PopulateFeature_ReturnsViewsFromAllAvailableApplicationParts()
|
public void PopulateFeature_ReturnsViewsFromAllAvailableApplicationParts()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var applicationPart1 = new Mock<ApplicationPart>();
|
var part1 = new AssemblyPart(typeof(object).GetTypeInfo().Assembly);
|
||||||
var viewsProvider1 = applicationPart1
|
var part2 = new AssemblyPart(GetType().GetTypeInfo().Assembly);
|
||||||
.As<IViewsProvider>()
|
var featureProvider = new TestableViewsFeatureProvider(new Dictionary<AssemblyPart, Type>
|
||||||
.SetupGet(p => p.Views)
|
{
|
||||||
.Returns(new[]
|
{ part1, typeof(ViewInfoContainer1) },
|
||||||
{
|
{ part2, typeof(ViewInfoContainer2) },
|
||||||
new ViewInfo("/Views/test/Index.cshtml", typeof(object))
|
});
|
||||||
});
|
|
||||||
var applicationPart2 = new Mock<ApplicationPart>();
|
|
||||||
var viewsProvider2 = applicationPart2
|
|
||||||
.As<IViewsProvider>()
|
|
||||||
.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 applicationPartManager = new ApplicationPartManager();
|
var applicationPartManager = new ApplicationPartManager();
|
||||||
applicationPartManager.ApplicationParts.Add(applicationPart1.Object);
|
applicationPartManager.ApplicationParts.Add(part1);
|
||||||
applicationPartManager.ApplicationParts.Add(applicationPart2.Object);
|
applicationPartManager.ApplicationParts.Add(part2);
|
||||||
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
|
applicationPartManager.FeatureProviders.Add(featureProvider);
|
||||||
var feature = new MetadataReferenceFeature();
|
var feature = new ViewsFeature();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
applicationPartManager.PopulateFeature(feature);
|
applicationPartManager.PopulateFeature(feature);
|
||||||
|
|
||||||
// Assert
|
// 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<AssemblyPart, Type> _containerLookup;
|
||||||
|
|
||||||
|
public TestableViewsFeatureProvider(Dictionary<AssemblyPart, Type> 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))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue