Added a view component tag helper descriptor factory (#5189)

This commit is contained in:
Crystal Qian 2016-08-31 17:31:04 -07:00 committed by GitHub
parent 34a4c8c191
commit df81f8be57
4 changed files with 401 additions and 0 deletions

View File

@ -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);
}
}

View File

@ -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)}";
}
}

View File

@ -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;
}
}
}

View File

@ -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
};
}
}
}
}