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