[Fixes #4087] Add support for AddTagHelpersAsServices()
* Added TagHelperFeature and TagHelperFeatureProvider to perform tag helper discovery. * Changed tag helper discovery to use application parts when using tag helpers as services. * Added FeatureTagHelperTypeResolver to resolve tag helper type definitions from the list of application parts. * Added AddTagHelpersAsServices extension method on IMvcBuilder and IMvcCoreBuilder that performs tag helper discovery through the ApplicationPartManager and registers those tag helpers as services in the service collection. Assemblies should be added to the ApplicationPartManager in order to discover tag helpers in them in them. The @addTagHelper directive is still required on Razor pages to indicate what tag helpers to use.
This commit is contained in:
parent
384fd1f218
commit
574ecbb3eb
|
|
@ -143,9 +143,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
/// Initializes a new instance of <see cref="MvcRazorHost"/> using the specified <paramref name="chunkTreeCache"/>.
|
||||
/// </summary>
|
||||
/// <param name="chunkTreeCache">An <see cref="IChunkTreeCache"/> rooted at the application base path.</param>
|
||||
public MvcRazorHost(IChunkTreeCache chunkTreeCache)
|
||||
/// <param name="resolver">The <see cref="ITagHelperDescriptorResolver"/> used to resolve tag helpers on razor views.</param>
|
||||
public MvcRazorHost(IChunkTreeCache chunkTreeCache, ITagHelperDescriptorResolver resolver)
|
||||
: this(chunkTreeCache, new RazorPathNormalizer())
|
||||
{
|
||||
TagHelperDescriptorResolver = resolver;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -2,13 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
|
|
@ -41,6 +38,23 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers tag helpers as services and replaces the existing <see cref="ITagHelperActivator"/>
|
||||
/// with an <see cref="ServiceBasedTagHelperActivator"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/> instance this method extends.</param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/> instance this method extends.</returns>
|
||||
public static IMvcBuilder AddTagHelpersAsServices(this IMvcBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
TagHelpersAsServices.AddTagHelpersAsServices(builder.PartManager, builder.Services);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an initialization callback for a given <typeparamref name="TTagHelper"/>.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -2,17 +2,20 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Directives;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
|
|
@ -26,6 +29,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
}
|
||||
|
||||
builder.AddViews();
|
||||
AddRazorViewEngineFeatureProviders(builder);
|
||||
AddRazorViewEngineServices(builder.Services);
|
||||
return builder;
|
||||
}
|
||||
|
|
@ -45,6 +49,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
}
|
||||
|
||||
builder.AddViews();
|
||||
|
||||
AddRazorViewEngineFeatureProviders(builder);
|
||||
AddRazorViewEngineServices(builder.Services);
|
||||
|
||||
if (setupAction != null)
|
||||
|
|
@ -55,6 +61,31 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
private static void AddRazorViewEngineFeatureProviders(IMvcCoreBuilder builder)
|
||||
{
|
||||
if (!builder.PartManager.FeatureProviders.OfType<TagHelperFeatureProvider>().Any())
|
||||
{
|
||||
builder.PartManager.FeatureProviders.Add(new TagHelperFeatureProvider());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers discovered tag helpers as services and changes the existing <see cref="ITagHelperActivator"/>
|
||||
/// for an <see cref="ServiceBasedTagHelperActivator"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcCoreBuilder"/> instance this method extends.</param>
|
||||
/// <returns>The <see cref="IMvcCoreBuilder"/> instance this method extends.</returns>
|
||||
public static IMvcCoreBuilder AddTagHelpersAsServices(this IMvcCoreBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
TagHelpersAsServices.AddTagHelpersAsServices(builder.PartManager, builder.Services);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an initialization callback for a given <typeparamref name="TTagHelper"/>.
|
||||
/// </summary>
|
||||
|
|
@ -116,6 +147,10 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return new DefaultChunkTreeCache(accessor.FileProvider);
|
||||
}));
|
||||
|
||||
services.TryAddSingleton<ITagHelperTypeResolver, TagHelperTypeResolver>();
|
||||
services.TryAddSingleton<ITagHelperDescriptorFactory>(s => new TagHelperDescriptorFactory(designTime: false));
|
||||
services.TryAddSingleton<ITagHelperDescriptorResolver, TagHelperDescriptorResolver>();
|
||||
|
||||
// Caches compilation artifacts across the lifetime of the application.
|
||||
services.TryAddSingleton<ICompilerCacheProvider, DefaultCompilerCacheProvider>();
|
||||
|
||||
|
|
@ -123,7 +158,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
// creating the singleton RazorViewEngine instance.
|
||||
services.TryAddTransient<IRazorPageFactoryProvider, DefaultRazorPageFactoryProvider>();
|
||||
services.TryAddTransient<IRazorCompilationService, RazorCompilationService>();
|
||||
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
|
||||
services.TryAddTransient<IMvcRazorHost,MvcRazorHost>();
|
||||
|
||||
// This caches Razor page activation details that are valid for the lifetime of the application.
|
||||
services.TryAddSingleton<IRazorPageActivator, RazorPageActivator>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// 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.Rendering;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="ITagHelperActivator"/> that retrieves tag helpers as services from the request's
|
||||
/// <see cref="IServiceProvider"/>.
|
||||
/// </summary>
|
||||
public class ServiceBasedTagHelperActivator : ITagHelperActivator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public TTagHelper Create<TTagHelper>(ViewContext context) where TTagHelper : ITagHelper
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
return context.HttpContext.RequestServices.GetRequiredService<TTagHelper>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 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.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
public static class TagHelpersAsServices
|
||||
{
|
||||
public static void AddTagHelpersAsServices(ApplicationPartManager manager, IServiceCollection services)
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
}
|
||||
|
||||
if (services == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(services));
|
||||
}
|
||||
|
||||
var feature = new TagHelperFeature();
|
||||
manager.PopulateFeature(feature);
|
||||
|
||||
foreach (var type in feature.TagHelpers.Select(t => t.AsType()))
|
||||
{
|
||||
services.TryAddTransient(type, type);
|
||||
}
|
||||
|
||||
services.Replace(ServiceDescriptor.Transient<ITagHelperActivator, ServiceBasedTagHelperActivator>());
|
||||
services.Replace(ServiceDescriptor.Transient<ITagHelperTypeResolver, FeatureTagHelperTypeResolver>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// 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 Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves tag helper types from the <see cref="ApplicationPartManager.ApplicationParts"/>
|
||||
/// of the application.
|
||||
/// </summary>
|
||||
public class FeatureTagHelperTypeResolver : TagHelperTypeResolver
|
||||
{
|
||||
private readonly TagHelperFeature _feature;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="FeatureTagHelperTypeResolver"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="manager">The <see cref="ApplicationPartManager"/> of the application.</param>
|
||||
public FeatureTagHelperTypeResolver(ApplicationPartManager manager)
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
}
|
||||
|
||||
_feature = new TagHelperFeature();
|
||||
manager.PopulateFeature(_feature);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<TypeInfo> GetExportedTypes(AssemblyName assemblyName)
|
||||
{
|
||||
if (assemblyName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assemblyName));
|
||||
}
|
||||
|
||||
var results = new List<TypeInfo>();
|
||||
for (var i = 0; i < _feature.TagHelpers.Count; i++)
|
||||
{
|
||||
var tagHelperAssemblyName = _feature.TagHelpers[i].Assembly.GetName();
|
||||
|
||||
if (AssemblyNameComparer.OrdinalIgnoreCase.Equals(tagHelperAssemblyName, assemblyName))
|
||||
{
|
||||
results.Add(_feature.TagHelpers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected sealed override bool IsTagHelper(TypeInfo typeInfo)
|
||||
{
|
||||
// Return true always as we have already decided what types are tag helpers when GetExportedTypes
|
||||
// gets called.
|
||||
return true;
|
||||
}
|
||||
|
||||
private class AssemblyNameComparer : IEqualityComparer<AssemblyName>
|
||||
{
|
||||
public static readonly IEqualityComparer<AssemblyName> OrdinalIgnoreCase = new AssemblyNameComparer();
|
||||
|
||||
private AssemblyNameComparer()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(AssemblyName x, AssemblyName y)
|
||||
{
|
||||
// Ignore case because that's what Assembly.Load does.
|
||||
return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(x.CultureName ?? string.Empty, y.CultureName ?? string.Empty, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(AssemblyName obj)
|
||||
{
|
||||
var hashCode = 0;
|
||||
if (obj.Name != null)
|
||||
{
|
||||
hashCode ^= obj.Name.GetHashCode();
|
||||
}
|
||||
|
||||
hashCode ^= (obj.CultureName ?? string.Empty).GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of tag helper types in an MVC application. The <see cref="TagHelperFeature"/> can be populated
|
||||
/// using the <see cref="ApplicationPartManager"/> that is available during startup at <see cref="IMvcBuilder.PartManager"/>
|
||||
/// and <see cref="IMvcCoreBuilder.PartManager"/> or at a later stage by requiring the <see cref="ApplicationPartManager"/>
|
||||
/// as a dependency in a component.
|
||||
/// </summary>
|
||||
public class TagHelperFeature
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the list of tag helper types in an MVC application.
|
||||
/// </summary>
|
||||
public IList<TypeInfo> TagHelpers { get; } = new List<TypeInfo>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Discovers tag helpers from a list of <see cref="ApplicationPart"/> instances.
|
||||
/// </summary>
|
||||
public class TagHelperFeatureProvider : IApplicationFeatureProvider<TagHelperFeature>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, TagHelperFeature feature)
|
||||
{
|
||||
foreach (var type in parts.OfType<IApplicationPartTypeProvider>())
|
||||
{
|
||||
ProcessPart(type, feature);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessPart(IApplicationPartTypeProvider part, TagHelperFeature feature)
|
||||
{
|
||||
foreach (var type in part.Types)
|
||||
{
|
||||
if (TagHelperConventions.IsTagHelper(type) && !feature.TagHelpers.Contains(type))
|
||||
{
|
||||
feature.TagHelpers.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
|
|
@ -29,6 +34,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
builder.AddApiExplorer();
|
||||
builder.AddAuthorization();
|
||||
|
||||
AddDefaultFrameworkParts(builder.PartManager);
|
||||
|
||||
// Order added affects options setup order
|
||||
|
||||
// Default framework order
|
||||
|
|
@ -48,6 +55,21 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return new MvcBuilder(builder.Services, builder.PartManager);
|
||||
}
|
||||
|
||||
private static void AddDefaultFrameworkParts(ApplicationPartManager partManager)
|
||||
{
|
||||
var mvcTagHelpersAssembly = typeof(InputTagHelper).GetTypeInfo().Assembly;
|
||||
if(!partManager.ApplicationParts.OfType<AssemblyPart>().Any(p => p.Assembly == mvcTagHelpersAssembly))
|
||||
{
|
||||
partManager.ApplicationParts.Add(new AssemblyPart(mvcTagHelpersAssembly));
|
||||
}
|
||||
|
||||
var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly;
|
||||
if(!partManager.ApplicationParts.OfType<AssemblyPart>().Any(p => p.Assembly == mvcRazorAssembly))
|
||||
{
|
||||
partManager.ApplicationParts.Add(new AssemblyPart(mvcRazorAssembly));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds MVC services to the specified <see cref="IServiceCollection" />.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// 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.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class TagHelpersFromServicesTest : IClassFixture<MvcTestFixture<ControllersFromServicesWebSite.Startup>>
|
||||
{
|
||||
public TagHelpersFromServicesTest(MvcTestFixture<ControllersFromServicesWebSite.Startup> fixture)
|
||||
{
|
||||
Client = fixture.Client;
|
||||
}
|
||||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Fact]
|
||||
public async Task TagHelpersWithConstructorInjectionAreCreatedAndActivated()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "3";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/another/inservicestaghelper");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, responseText.Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Razor.Chunks;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Directives
|
||||
|
|
@ -31,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives
|
|||
new UsingChunk { Namespace = "AppNamespace.Model" },
|
||||
};
|
||||
var cache = new DefaultChunkTreeCache(fileProvider);
|
||||
using (var host = new MvcRazorHost(cache))
|
||||
using (var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)))
|
||||
{
|
||||
var utility = new ChunkInheritanceUtility(host, cache, defaultChunks);
|
||||
|
||||
|
|
@ -119,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives
|
|||
fileProvider.AddFile(@"/Views/_Layout.cshtml", string.Empty);
|
||||
fileProvider.AddFile(@"/Views/home/_not-viewimports.cshtml", string.Empty);
|
||||
var cache = new DefaultChunkTreeCache(fileProvider);
|
||||
using (var host = new MvcRazorHost(cache))
|
||||
using (var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)))
|
||||
{
|
||||
var defaultChunks = new Chunk[]
|
||||
{
|
||||
|
|
@ -144,7 +145,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives
|
|||
fileProvider.AddFile(@"/Views/_ViewImports.cshtml",
|
||||
"@inject DifferentHelper<TModel> Html");
|
||||
var cache = new DefaultChunkTreeCache(fileProvider);
|
||||
using (var host = new MvcRazorHost(cache))
|
||||
using (var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)))
|
||||
{
|
||||
var defaultChunks = new Chunk[]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.Chunks;
|
|||
using Microsoft.AspNetCore.Razor.Chunks.Generators;
|
||||
using Microsoft.AspNetCore.Razor.CodeGenerators;
|
||||
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||
|
|
@ -149,7 +150,7 @@ MyType1
|
|||
var chunkTreeCache = new DefaultChunkTreeCache(new TestFileProvider());
|
||||
return new CodeGeneratorContext(
|
||||
new ChunkGeneratorContext(
|
||||
new MvcRazorHost(chunkTreeCache),
|
||||
new MvcRazorHost(chunkTreeCache, new TagHelperDescriptorResolver(designTime: false)),
|
||||
"MyClass",
|
||||
"MyNamespace",
|
||||
string.Empty,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ using Microsoft.AspNetCore.Razor.Chunks.Generators;
|
|||
using Microsoft.AspNetCore.Razor.CodeGenerators;
|
||||
using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors;
|
||||
using Microsoft.AspNetCore.Razor.Parser;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
{
|
||||
// Arrange
|
||||
var fileProvider = new TestFileProvider();
|
||||
using (var host = new MvcRazorHost(new DefaultChunkTreeCache(fileProvider)))
|
||||
using (var host = new MvcRazorHost(new DefaultChunkTreeCache(fileProvider), new TagHelperDescriptorResolver(designTime: false)))
|
||||
{
|
||||
// Act
|
||||
var instrumented = host.EnableInstrumentation;
|
||||
|
|
@ -594,7 +595,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
private class MvcRazorHostWithNormalizedNewLine : MvcRazorHost
|
||||
{
|
||||
public MvcRazorHostWithNormalizedNewLine(IChunkTreeCache codeTreeCache)
|
||||
: base(codeTreeCache)
|
||||
: base(codeTreeCache, new TagHelperDescriptorResolver(designTime: false))
|
||||
{ }
|
||||
|
||||
public override CodeGenerator DecorateCodeGenerator(
|
||||
|
|
@ -646,7 +647,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
private class TestMvcRazorHost : MvcRazorHost
|
||||
{
|
||||
public TestMvcRazorHost(IChunkTreeCache ChunkTreeCache)
|
||||
: base(ChunkTreeCache)
|
||||
: base(ChunkTreeCache, new TagHelperDescriptorResolver(designTime: false))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
// 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;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Test.DependencyInjection
|
||||
{
|
||||
public class MvcRazorMvcBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddTagHelpersAsServices_ReplacesTagHelperActivatorAndTagHelperTypeResolver()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
var builder = services
|
||||
.AddMvc()
|
||||
.ConfigureApplicationPartManager(manager =>
|
||||
{
|
||||
manager.ApplicationParts.Add(new TestApplicationPart());
|
||||
manager.FeatureProviders.Add(new TagHelperFeatureProvider());
|
||||
});
|
||||
|
||||
// Act
|
||||
builder.AddTagHelpersAsServices();
|
||||
|
||||
// Assert
|
||||
var activatorDescriptor = Assert.Single(services.ToList(), d => d.ServiceType == typeof(ITagHelperActivator));
|
||||
Assert.Equal(typeof(ServiceBasedTagHelperActivator), activatorDescriptor.ImplementationType);
|
||||
|
||||
var resolverDescriptor = Assert.Single(services.ToList(), d => d.ServiceType == typeof(ITagHelperTypeResolver));
|
||||
Assert.Equal(typeof(FeatureTagHelperTypeResolver), resolverDescriptor.ImplementationType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTagHelpersAsServices_RegistersDiscoveredTagHelpers()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
|
||||
var manager = new ApplicationPartManager();
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(
|
||||
typeof(TestTagHelperOne),
|
||||
typeof(TestTagHelperTwo)));
|
||||
|
||||
manager.FeatureProviders.Add(new TestFeatureProvider());
|
||||
|
||||
var builder = new MvcBuilder(services, manager);
|
||||
|
||||
// Act
|
||||
builder.AddTagHelpersAsServices();
|
||||
|
||||
// Assert
|
||||
var collection = services.ToList();
|
||||
Assert.Equal(4, collection.Count);
|
||||
|
||||
var tagHelperOne = Assert.Single(collection,t => t.ServiceType == typeof(TestTagHelperOne));
|
||||
Assert.Equal(typeof(TestTagHelperOne), tagHelperOne.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, tagHelperOne.Lifetime);
|
||||
|
||||
var tagHelperTwo = Assert.Single(collection, t => t.ServiceType == typeof(TestTagHelperTwo));
|
||||
Assert.Equal(typeof(TestTagHelperTwo), tagHelperTwo.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, tagHelperTwo.Lifetime);
|
||||
|
||||
var activator = Assert.Single(collection, t => t.ServiceType == typeof(ITagHelperActivator));
|
||||
Assert.Equal(typeof(ServiceBasedTagHelperActivator), activator.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, activator.Lifetime);
|
||||
|
||||
var typeResolver = Assert.Single(collection, t => t.ServiceType == typeof(ITagHelperTypeResolver));
|
||||
Assert.Equal(typeof(FeatureTagHelperTypeResolver), typeResolver.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, typeResolver.Lifetime);
|
||||
}
|
||||
|
||||
private class TestTagHelperOne : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
private class TestTagHelperTwo : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
private class TestFeatureProvider : IApplicationFeatureProvider<TagHelperFeature>
|
||||
{
|
||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, TagHelperFeature feature)
|
||||
{
|
||||
foreach (var type in parts.OfType<IApplicationPartTypeProvider>().SelectMany(tp => tp.Types))
|
||||
{
|
||||
feature.TagHelpers.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// 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;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Test.DependencyInjection
|
||||
{
|
||||
public class MvcRazorMvcCoreBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddTagHelpersAsServices_ReplacesTagHelperActivatorAndTagHelperTypeResolver()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
var builder = services
|
||||
.AddMvcCore()
|
||||
.ConfigureApplicationPartManager(manager =>
|
||||
{
|
||||
manager.ApplicationParts.Add(new TestApplicationPart());
|
||||
manager.FeatureProviders.Add(new TagHelperFeatureProvider());
|
||||
});
|
||||
|
||||
// Act
|
||||
builder.AddTagHelpersAsServices();
|
||||
|
||||
// Assert
|
||||
var activatorDescriptor = Assert.Single(services.ToList(), d => d.ServiceType == typeof(ITagHelperActivator));
|
||||
Assert.Equal(typeof(ServiceBasedTagHelperActivator), activatorDescriptor.ImplementationType);
|
||||
|
||||
var resolverDescriptor = Assert.Single(services.ToList(), d => d.ServiceType == typeof(ITagHelperTypeResolver));
|
||||
Assert.Equal(typeof(FeatureTagHelperTypeResolver), resolverDescriptor.ImplementationType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTagHelpersAsServices_RegistersDiscoveredTagHelpers()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
|
||||
var manager = new ApplicationPartManager();
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(
|
||||
typeof(TestTagHelperOne),
|
||||
typeof(TestTagHelperTwo)));
|
||||
|
||||
manager.FeatureProviders.Add(new TestFeatureProvider());
|
||||
|
||||
var builder = new MvcCoreBuilder(services, manager);
|
||||
|
||||
// Act
|
||||
builder.AddTagHelpersAsServices();
|
||||
|
||||
// Assert
|
||||
var collection = services.ToList();
|
||||
Assert.Equal(4, collection.Count);
|
||||
|
||||
var tagHelperOne = Assert.Single(collection, t => t.ServiceType == typeof(TestTagHelperOne));
|
||||
Assert.Equal(typeof(TestTagHelperOne), tagHelperOne.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, tagHelperOne.Lifetime);
|
||||
|
||||
var tagHelperTwo = Assert.Single(collection, t => t.ServiceType == typeof(TestTagHelperTwo));
|
||||
Assert.Equal(typeof(TestTagHelperTwo), tagHelperTwo.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, tagHelperTwo.Lifetime);
|
||||
|
||||
var activator = Assert.Single(collection, t => t.ServiceType == typeof(ITagHelperActivator));
|
||||
Assert.Equal(typeof(ServiceBasedTagHelperActivator), activator.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, activator.Lifetime);
|
||||
|
||||
var typeResolver = Assert.Single(collection, t => t.ServiceType == typeof(ITagHelperTypeResolver));
|
||||
Assert.Equal(typeof(FeatureTagHelperTypeResolver), typeResolver.ImplementationType);
|
||||
Assert.Equal(ServiceLifetime.Transient, typeResolver.Lifetime);
|
||||
}
|
||||
|
||||
private class TestTagHelperOne : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
private class TestTagHelperTwo : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
private class TestFeatureProvider : IApplicationFeatureProvider<TagHelperFeature>
|
||||
{
|
||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, TagHelperFeature feature)
|
||||
{
|
||||
foreach (var type in parts.OfType<IApplicationPartTypeProvider>().SelectMany(tp => tp.Types))
|
||||
{
|
||||
feature.TagHelpers.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// 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 Microsoft.AspNetCore.Mvc.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
public class FeatureTagHelperTypeResolverTest
|
||||
{
|
||||
[Fact]
|
||||
public void Resolve_ReturnsTagHelpers_FromApplicationParts()
|
||||
{
|
||||
// Arrange
|
||||
var manager = new ApplicationPartManager();
|
||||
var types = new[] { typeof(TestTagHelper) };
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(types));
|
||||
manager.FeatureProviders.Add(new TestFeatureProvider());
|
||||
|
||||
var resolver = new FeatureTagHelperTypeResolver(manager);
|
||||
|
||||
var assemblyName = typeof(FeatureTagHelperTypeResolverTest).GetTypeInfo().Assembly.GetName().Name;
|
||||
|
||||
// Act
|
||||
var result = resolver.Resolve(assemblyName, SourceLocation.Undefined, new ErrorSink());
|
||||
|
||||
// Assert
|
||||
var type = Assert.Single(result);
|
||||
Assert.Equal(typeof(TestTagHelper), type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Resolve_ReturnsTagHelpers_FilteredByAssembly()
|
||||
{
|
||||
// Arrange
|
||||
var manager = new ApplicationPartManager();
|
||||
var types = new[] { typeof(TestTagHelper) };
|
||||
manager.ApplicationParts.Add(new AssemblyPart(typeof(InputTagHelper).GetTypeInfo().Assembly));
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(types));
|
||||
manager.FeatureProviders.Add(new TestFeatureProvider());
|
||||
|
||||
var resolver = new FeatureTagHelperTypeResolver(manager);
|
||||
|
||||
var assemblyName = typeof(FeatureTagHelperTypeResolverTest).GetTypeInfo().Assembly.GetName().Name;
|
||||
|
||||
// Act
|
||||
var result = resolver.Resolve(assemblyName, SourceLocation.Undefined, new ErrorSink());
|
||||
|
||||
// Assert
|
||||
var type = Assert.Single(result);
|
||||
Assert.Equal(typeof(TestTagHelper), type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Resolve_ReturnsEmptyTypesList_IfAssemblyLoadFails()
|
||||
{
|
||||
// Arrange
|
||||
var manager = new ApplicationPartManager();
|
||||
var types = new[] { typeof(TestTagHelper) };
|
||||
manager.ApplicationParts.Add(new AssemblyPart(typeof(InputTagHelper).GetTypeInfo().Assembly));
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(types));
|
||||
manager.FeatureProviders.Add(new TestFeatureProvider());
|
||||
|
||||
var resolver = new FeatureTagHelperTypeResolver(manager);
|
||||
|
||||
// Act
|
||||
var result = resolver.Resolve("UnknownAssembly", SourceLocation.Undefined, new ErrorSink());
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
private class TestFeatureProvider : IApplicationFeatureProvider<TagHelperFeature>
|
||||
{
|
||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, TagHelperFeature feature)
|
||||
{
|
||||
foreach (var type in parts.OfType<IApplicationPartTypeProvider>().SelectMany(tp => tp.Types))
|
||||
{
|
||||
feature.TagHelpers.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TestTagHelper : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
private class NotInPartsTagHelper : TagHelper
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// 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;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers.TagHelperFeatureProviderTests;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
public class TagHelperFeatureProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void Populate_IncludesTagHelpers()
|
||||
{
|
||||
// Arrange
|
||||
var manager = new ApplicationPartManager();
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(typeof(DiscoveryTagHelper)));
|
||||
manager.FeatureProviders.Add(new TagHelperFeatureProvider());
|
||||
|
||||
var feature = new TagHelperFeature();
|
||||
|
||||
// Act
|
||||
manager.PopulateFeature(feature);
|
||||
|
||||
// Assert
|
||||
var tagHelperType = Assert.Single(feature.TagHelpers, th => th == typeof(DiscoveryTagHelper).GetTypeInfo());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Populate_DoesNotIncludeDuplicateTagHelpers()
|
||||
{
|
||||
// Arrange
|
||||
var manager = new ApplicationPartManager();
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(typeof(DiscoveryTagHelper)));
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(typeof(DiscoveryTagHelper)));
|
||||
manager.FeatureProviders.Add(new TagHelperFeatureProvider());
|
||||
|
||||
var feature = new TagHelperFeature();
|
||||
|
||||
// Act
|
||||
manager.PopulateFeature(feature);
|
||||
|
||||
// Assert
|
||||
var tagHelperType = Assert.Single(feature.TagHelpers, th => th == typeof(DiscoveryTagHelper).GetTypeInfo());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Populate_OnlyRunsOnPartsThatExportTypes()
|
||||
{
|
||||
// Arrange
|
||||
var manager = new ApplicationPartManager();
|
||||
manager.ApplicationParts.Add(new TestApplicationPart(typeof(DiscoveryTagHelper)));
|
||||
manager.ApplicationParts.Add(new NonApplicationTypeProviderPart());
|
||||
manager.FeatureProviders.Add(new TagHelperFeatureProvider());
|
||||
|
||||
var feature = new TagHelperFeature();
|
||||
|
||||
// Act
|
||||
manager.PopulateFeature(feature);
|
||||
|
||||
// Assert
|
||||
var tagHelperType = Assert.Single(feature.TagHelpers, th => th == typeof(DiscoveryTagHelper).GetTypeInfo());
|
||||
}
|
||||
|
||||
private class NonApplicationTypeProviderPart : ApplicationPart
|
||||
{
|
||||
public override string Name => nameof(NonApplicationTypeProviderPart);
|
||||
|
||||
public IEnumerable<TypeInfo> Types => new[] { typeof(AnotherTagHelper).GetTypeInfo() };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These types need to be public for the test to work.
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers.TagHelperFeatureProviderTests
|
||||
{
|
||||
public class DiscoveryTagHelper : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
public class AnotherTagHelper : TagHelper
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// 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
|
||||
{
|
||||
public class TestApplicationPart : ApplicationPart, IApplicationPartTypeProvider
|
||||
{
|
||||
public TestApplicationPart()
|
||||
{
|
||||
Types = Enumerable.Empty<TypeInfo>();
|
||||
}
|
||||
|
||||
public TestApplicationPart(params TypeInfo[] types)
|
||||
{
|
||||
Types = types;
|
||||
}
|
||||
|
||||
public TestApplicationPart(IEnumerable<TypeInfo> types)
|
||||
{
|
||||
Types = types;
|
||||
}
|
||||
|
||||
public TestApplicationPart(IEnumerable<Type> types)
|
||||
:this(types.Select(t => t.GetTypeInfo()))
|
||||
{
|
||||
}
|
||||
|
||||
public TestApplicationPart(params Type[] types)
|
||||
: this(types.Select(t => t.GetTypeInfo()))
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name => "Test part";
|
||||
|
||||
public IEnumerable<TypeInfo> Types { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Mvc.DataAnnotations": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Mvc.Formatters.Xml": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Mvc.Razor": "1.0.0-*",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
|
|||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
|
|
@ -124,6 +126,61 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddMvc_AddsAssemblyPartsForFrameworkTagHelpers()
|
||||
{
|
||||
// Arrange
|
||||
var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly;
|
||||
var mvcTagHelpersAssembly = typeof(InputTagHelper).GetTypeInfo().Assembly;
|
||||
var services = new ServiceCollection();
|
||||
var providers = new IApplicationFeatureProvider[]
|
||||
{
|
||||
new ControllerFeatureProvider(),
|
||||
new ViewComponentFeatureProvider()
|
||||
};
|
||||
|
||||
// Act
|
||||
services.AddMvc();
|
||||
|
||||
// Assert
|
||||
var descriptor = Assert.Single(services, d => d.ServiceType == typeof(ApplicationPartManager));
|
||||
Assert.Equal(ServiceLifetime.Singleton, descriptor.Lifetime);
|
||||
Assert.NotNull(descriptor.ImplementationInstance);
|
||||
var manager = Assert.IsType<ApplicationPartManager>(descriptor.ImplementationInstance);
|
||||
|
||||
Assert.Equal(2, manager.ApplicationParts.Count);
|
||||
Assert.Single(manager.ApplicationParts.OfType<AssemblyPart>(), p => p.Assembly == mvcRazorAssembly);
|
||||
Assert.Single(manager.ApplicationParts.OfType<AssemblyPart>(), p => p.Assembly == mvcTagHelpersAssembly);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddMvcTwice_DoesNotAddDuplicateFramewokrParts()
|
||||
{
|
||||
// Arrange
|
||||
var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly;
|
||||
var mvcTagHelpersAssembly = typeof(InputTagHelper).GetTypeInfo().Assembly;
|
||||
var services = new ServiceCollection();
|
||||
var providers = new IApplicationFeatureProvider[]
|
||||
{
|
||||
new ControllerFeatureProvider(),
|
||||
new ViewComponentFeatureProvider()
|
||||
};
|
||||
|
||||
// Act
|
||||
services.AddMvc();
|
||||
services.AddMvc();
|
||||
|
||||
// Assert
|
||||
var descriptor = Assert.Single(services, d => d.ServiceType == typeof(ApplicationPartManager));
|
||||
Assert.Equal(ServiceLifetime.Singleton, descriptor.Lifetime);
|
||||
Assert.NotNull(descriptor.ImplementationInstance);
|
||||
var manager = Assert.IsType<ApplicationPartManager>(descriptor.ImplementationInstance);
|
||||
|
||||
Assert.Equal(2, manager.ApplicationParts.Count);
|
||||
Assert.Single(manager.ApplicationParts.OfType<AssemblyPart>(), p => p.Assembly == mvcRazorAssembly);
|
||||
Assert.Single(manager.ApplicationParts.OfType<AssemblyPart>(), p => p.Assembly == mvcTagHelpersAssembly);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddMvcTwice_DoesNotAddApplicationFeatureProvidersTwice()
|
||||
{
|
||||
|
|
@ -145,9 +202,10 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
Assert.NotNull(descriptor.ImplementationInstance);
|
||||
var manager = Assert.IsType<ApplicationPartManager>(descriptor.ImplementationInstance);
|
||||
|
||||
Assert.Equal(2, manager.FeatureProviders.Count);
|
||||
Assert.Equal(3, manager.FeatureProviders.Count);
|
||||
Assert.IsType<ControllerFeatureProvider>(manager.FeatureProviders[0]);
|
||||
Assert.IsType<ViewComponentFeatureProvider>(manager.FeatureProviders[1]);
|
||||
Assert.IsType<TagHelperFeatureProvider>(manager.FeatureProviders[2]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -19,5 +19,11 @@ namespace ControllersFromServicesWebSite
|
|||
{
|
||||
return ViewComponent("ComponentFromServices");
|
||||
}
|
||||
|
||||
[HttpGet("InServicesTagHelper")]
|
||||
public IActionResult InServicesTagHelper()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using ControllersFromServicesClassLibrary;
|
||||
using ControllersFromServicesWebSite.Components;
|
||||
using ControllersFromServicesWebSite.TagHelpers;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
@ -25,9 +26,11 @@ namespace ControllersFromServicesWebSite
|
|||
.AddApplicationPart(typeof(TimeScheduleController).GetTypeInfo().Assembly)
|
||||
.ConfigureApplicationPartManager(manager => manager.ApplicationParts.Add(new TypesPart(
|
||||
typeof(AnotherController),
|
||||
typeof(ComponentFromServicesViewComponent))))
|
||||
typeof(ComponentFromServicesViewComponent),
|
||||
typeof(InServicesTagHelper))))
|
||||
.AddControllersAsServices()
|
||||
.AddViewComponentsAsServices();
|
||||
.AddViewComponentsAsServices()
|
||||
.AddTagHelpersAsServices();
|
||||
|
||||
services.AddTransient<QueryValueService>();
|
||||
services.AddTransient<ValueService>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace ControllersFromServicesWebSite.TagHelpers
|
||||
{
|
||||
[HtmlTargetElement("InServices")]
|
||||
public class InServicesTagHelper : TagHelper
|
||||
{
|
||||
private ValueService _value;
|
||||
|
||||
public InServicesTagHelper(ValueService value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.TagName = null;
|
||||
output.Content.SetContent(_value.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
@addTagHelper *, ControllersFromServicesWebSite
|
||||
<inservices></inservices>
|
||||
Loading…
Reference in New Issue