Added a view component tag helper descriptor factory (#5189)
This commit is contained in:
parent
34a4c8c191
commit
df81f8be57
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A library of methods used to generate <see cref="TagHelperDescriptor"/>s for view components.
|
||||||
|
/// </summary>
|
||||||
|
public static class ViewComponentTagHelperDescriptorConventions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The key in a <see cref="TagHelperDescriptor.PropertyBag"/> containing
|
||||||
|
/// the short name of a view component.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string ViewComponentNameKey = "ViewComponentName";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether a <see cref="TagHelperDescriptor"/> represents a view component.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptor">The <see cref="TagHelperDescriptor"/> to check.</param>
|
||||||
|
/// <returns>Whether a <see cref="TagHelperDescriptor"/> represents a view component.</returns>
|
||||||
|
public static bool IsViewComponentDescriptor(TagHelperDescriptor descriptor) =>
|
||||||
|
descriptor != null && descriptor.PropertyBag.ContainsKey(ViewComponentNameKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
// 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.Razor.Host;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||||
|
using Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
|
||||||
|
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods to create tag helper representations of view components.
|
||||||
|
/// </summary>
|
||||||
|
public class ViewComponentTagHelperDescriptorFactory
|
||||||
|
{
|
||||||
|
private readonly IViewComponentDescriptorProvider _descriptorProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ViewComponentTagHelperDescriptorFactory"/>,
|
||||||
|
/// then creates <see cref="TagHelperDescriptor"/>s for <see cref="ViewComponent"/>s
|
||||||
|
/// in the given <see cref="IViewComponentDescriptorProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptorProvider">The provider of <see cref="ViewComponentDescriptor"/>s.</param>
|
||||||
|
public ViewComponentTagHelperDescriptorFactory(IViewComponentDescriptorProvider descriptorProvider)
|
||||||
|
{
|
||||||
|
if (descriptorProvider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(descriptorProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
_descriptorProvider = descriptorProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates <see cref="TagHelperDescriptor"/> representations of <see cref="ViewComponent"/>s
|
||||||
|
/// in an <see href="Assembly"/> represented by the given <paramref name="assemblyName"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assemblyName">The name of the assembly containing
|
||||||
|
/// the <see cref="ViewComponent"/>s to translate.</param>
|
||||||
|
/// <returns>A <see cref="IEnumerable{TagHelperDescriptor}"/>,
|
||||||
|
/// one for each <see cref="ViewComponent"/>.</returns>
|
||||||
|
public IEnumerable<TagHelperDescriptor> CreateDescriptors(string assemblyName)
|
||||||
|
{
|
||||||
|
if (assemblyName == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(assemblyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewComponentDescriptors = _descriptorProvider
|
||||||
|
.GetViewComponents()
|
||||||
|
.Where(viewComponent => string.Equals(assemblyName, viewComponent.TypeInfo.Assembly.GetName().Name,
|
||||||
|
StringComparison.Ordinal));
|
||||||
|
|
||||||
|
var tagHelperDescriptors = viewComponentDescriptors
|
||||||
|
.Select(viewComponentDescriptor => CreateDescriptor(viewComponentDescriptor));
|
||||||
|
|
||||||
|
return tagHelperDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TagHelperDescriptor CreateDescriptor(ViewComponentDescriptor viewComponentDescriptor)
|
||||||
|
{
|
||||||
|
var assemblyName = viewComponentDescriptor.TypeInfo.Assembly.GetName().Name;
|
||||||
|
var tagName = GetTagName(viewComponentDescriptor);
|
||||||
|
var typeName = $"__Generated__{viewComponentDescriptor.ShortName}ViewComponentTagHelper";
|
||||||
|
|
||||||
|
var tagHelperDescriptor = new TagHelperDescriptor
|
||||||
|
{
|
||||||
|
TagName = tagName,
|
||||||
|
TypeName = typeName,
|
||||||
|
AssemblyName = assemblyName
|
||||||
|
};
|
||||||
|
|
||||||
|
SetAttributeDescriptors(viewComponentDescriptor, tagHelperDescriptor);
|
||||||
|
|
||||||
|
tagHelperDescriptor.PropertyBag.Add(
|
||||||
|
ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, viewComponentDescriptor.ShortName);
|
||||||
|
|
||||||
|
return tagHelperDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAttributeDescriptors(ViewComponentDescriptor viewComponentDescriptor,
|
||||||
|
TagHelperDescriptor tagHelperDescriptor)
|
||||||
|
{
|
||||||
|
var methodParameters = viewComponentDescriptor.MethodInfo.GetParameters();
|
||||||
|
var attributeDescriptors = new List<TagHelperAttributeDescriptor>();
|
||||||
|
|
||||||
|
foreach (var parameter in methodParameters)
|
||||||
|
{
|
||||||
|
var lowerKebabName = TagHelperDescriptorFactory.ToHtmlCase(parameter.Name);
|
||||||
|
var descriptor = new TagHelperAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = lowerKebabName,
|
||||||
|
PropertyName = parameter.Name,
|
||||||
|
TypeName = parameter.ParameterType.FullName
|
||||||
|
};
|
||||||
|
|
||||||
|
descriptor.IsEnum = parameter.ParameterType.GetTypeInfo().IsEnum;
|
||||||
|
descriptor.IsIndexer = false;
|
||||||
|
|
||||||
|
attributeDescriptors.Add(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
tagHelperDescriptor.Attributes = attributeDescriptors;
|
||||||
|
tagHelperDescriptor.RequiredAttributes = tagHelperDescriptor.Attributes.Select(
|
||||||
|
attribute => new TagHelperRequiredAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = attribute.Name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTagName(ViewComponentDescriptor descriptor) =>
|
||||||
|
$"vc:{TagHelperDescriptorFactory.ToHtmlCase(descriptor.ShortName)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// 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.ViewComponents;
|
||||||
|
using Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test
|
||||||
|
{
|
||||||
|
public class ViewComponentTagHelperDescriptorConventionsTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void IsViewComponentDescriptor_ReturnsFalseForInvalidDescriptor()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
var tagHelperDescriptor = CreateTagHelperDescriptor();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var isViewComponentDescriptor = ViewComponentTagHelperDescriptorConventions
|
||||||
|
.IsViewComponentDescriptor(tagHelperDescriptor);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(isViewComponentDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsViewComponentDescriptor_ReturnsTrueForValidDescriptor()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = CreateViewComponentTagHelperDescriptor();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var isViewComponentDescriptor = ViewComponentTagHelperDescriptorConventions
|
||||||
|
.IsViewComponentDescriptor(descriptor);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(isViewComponentDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TagHelperDescriptor CreateTagHelperDescriptor()
|
||||||
|
{
|
||||||
|
var descriptor = new TagHelperDescriptor
|
||||||
|
{
|
||||||
|
TagName = "tag-name",
|
||||||
|
TypeName = "TypeName",
|
||||||
|
AssemblyName = "AssemblyName",
|
||||||
|
};
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TagHelperDescriptor CreateViewComponentTagHelperDescriptor()
|
||||||
|
{
|
||||||
|
var descriptor = CreateTagHelperDescriptor();
|
||||||
|
descriptor.PropertyBag.Add(
|
||||||
|
ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey,
|
||||||
|
"ViewComponentName");
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
// 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 System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor.Host;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||||
|
using Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Razor.Test.ViewComponentTagHelpers
|
||||||
|
{
|
||||||
|
public class ViewComponentTagHelperDescriptorFactoryTest
|
||||||
|
{
|
||||||
|
public static TheoryData AssemblyData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var provider = new TestViewComponentDescriptorProvider();
|
||||||
|
|
||||||
|
var assemblyOne = "Microsoft.AspNetCore.Mvc.Razor";
|
||||||
|
var assemblyTwo = "Microsoft.AspNetCore.Mvc.Razor.Test";
|
||||||
|
var assemblyNone = string.Empty;
|
||||||
|
|
||||||
|
return new TheoryData<string, IEnumerable<TagHelperDescriptor>>
|
||||||
|
{
|
||||||
|
{ assemblyOne, new [] { provider.GetTagHelperDescriptorOne() } },
|
||||||
|
{ assemblyTwo, new [] { provider.GetTagHelperDescriptorTwo() } },
|
||||||
|
{ assemblyNone, Enumerable.Empty<TagHelperDescriptor>() }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(AssemblyData))]
|
||||||
|
public void CreateDescriptors_ReturnsCorrectDescriptors(
|
||||||
|
string assemblyName,
|
||||||
|
IEnumerable<TagHelperDescriptor> expectedDescriptors)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new TestViewComponentDescriptorProvider();
|
||||||
|
var factory = new ViewComponentTagHelperDescriptorFactory(provider);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptors = factory.CreateDescriptors(assemblyName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedDescriptors, descriptors, TagHelperDescriptorComparer.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test invokes are needed for method creation in TestViewComponentDescriptorProvider.
|
||||||
|
public enum TestEnum
|
||||||
|
{
|
||||||
|
A = 1,
|
||||||
|
B = 2,
|
||||||
|
C = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TestInvokeOne(string foo, string bar)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TestInvokeTwo(TestEnum testEnum, Dictionary<string, int> testDictionary, int baz = 5)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestViewComponentDescriptorProvider : IViewComponentDescriptorProvider
|
||||||
|
{
|
||||||
|
private readonly ViewComponentDescriptor _viewComponentDescriptorOne = new ViewComponentDescriptor
|
||||||
|
{
|
||||||
|
DisplayName = "OneDisplayName",
|
||||||
|
FullName = "OneViewComponent",
|
||||||
|
ShortName = "One",
|
||||||
|
MethodInfo = typeof(ViewComponentTagHelperDescriptorFactoryTest)
|
||||||
|
.GetMethod(nameof(ViewComponentTagHelperDescriptorFactoryTest.TestInvokeOne)),
|
||||||
|
TypeInfo = typeof(ViewComponentTagHelperDescriptorFactory).GetTypeInfo()
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly ViewComponentDescriptor _viewComponentDescriptorTwo = new ViewComponentDescriptor
|
||||||
|
{
|
||||||
|
DisplayName = "TwoDisplayName",
|
||||||
|
FullName = "TwoViewComponent",
|
||||||
|
ShortName = "Two",
|
||||||
|
MethodInfo = typeof(ViewComponentTagHelperDescriptorFactoryTest)
|
||||||
|
.GetMethod(nameof(ViewComponentTagHelperDescriptorFactoryTest.TestInvokeTwo)),
|
||||||
|
TypeInfo = typeof(ViewComponentTagHelperDescriptorFactoryTest).GetTypeInfo()
|
||||||
|
};
|
||||||
|
|
||||||
|
public TagHelperDescriptor GetTagHelperDescriptorOne()
|
||||||
|
{
|
||||||
|
var descriptor = new TagHelperDescriptor
|
||||||
|
{
|
||||||
|
TagName = "vc:one",
|
||||||
|
TypeName = "__Generated__OneViewComponentTagHelper",
|
||||||
|
AssemblyName = "Microsoft.AspNetCore.Mvc.Razor",
|
||||||
|
Attributes = new List<TagHelperAttributeDescriptor>
|
||||||
|
{
|
||||||
|
new TagHelperAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "foo",
|
||||||
|
PropertyName = "foo",
|
||||||
|
TypeName = typeof(string).FullName
|
||||||
|
},
|
||||||
|
new TagHelperAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "bar",
|
||||||
|
PropertyName = "bar",
|
||||||
|
TypeName = typeof(string).FullName
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RequiredAttributes = new List<TagHelperRequiredAttributeDescriptor>
|
||||||
|
{
|
||||||
|
new TagHelperRequiredAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "foo"
|
||||||
|
},
|
||||||
|
new TagHelperRequiredAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
descriptor.PropertyBag.Add(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "One");
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagHelperDescriptor GetTagHelperDescriptorTwo()
|
||||||
|
{
|
||||||
|
var descriptor = new TagHelperDescriptor
|
||||||
|
{
|
||||||
|
TagName = "vc:two",
|
||||||
|
TypeName = "__Generated__TwoViewComponentTagHelper",
|
||||||
|
AssemblyName = "Microsoft.AspNetCore.Mvc.Razor.Test",
|
||||||
|
Attributes = new List<TagHelperAttributeDescriptor>
|
||||||
|
{
|
||||||
|
new TagHelperAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "test-enum",
|
||||||
|
PropertyName = "testEnum",
|
||||||
|
TypeName = typeof(TestEnum).FullName,
|
||||||
|
IsEnum = true
|
||||||
|
},
|
||||||
|
|
||||||
|
new TagHelperAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "test-dictionary",
|
||||||
|
PropertyName = "testDictionary",
|
||||||
|
TypeName = typeof(Dictionary<string, int>).FullName
|
||||||
|
},
|
||||||
|
|
||||||
|
new TagHelperAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "baz",
|
||||||
|
PropertyName = "baz",
|
||||||
|
TypeName = typeof(int).FullName
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RequiredAttributes = new List<TagHelperRequiredAttributeDescriptor>
|
||||||
|
{
|
||||||
|
new TagHelperRequiredAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "test-enum"
|
||||||
|
},
|
||||||
|
|
||||||
|
new TagHelperRequiredAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "test-dictionary"
|
||||||
|
},
|
||||||
|
|
||||||
|
new TagHelperRequiredAttributeDescriptor
|
||||||
|
{
|
||||||
|
Name = "baz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
descriptor.PropertyBag.Add(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "Two");
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ViewComponentDescriptor> GetViewComponents()
|
||||||
|
{
|
||||||
|
return new List<ViewComponentDescriptor>
|
||||||
|
{
|
||||||
|
_viewComponentDescriptorOne,
|
||||||
|
_viewComponentDescriptorTwo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue