未验证 提交 8d169332 编写于 作者: S Safia Abdalla 提交者: GitHub

Add support for default parameter values in ViewComponent tag helper (#32979)

Addresses https://github.com/dotnet/aspnetcore/issues/5011.

To implement support for optional parameters, we largely needed to do two things:

- Update the `ViewComponentTagHelperDescriptorFactory` that is responsible for constructing `VCTHD` objects to _not_ produce the `RequiredAttributeDescriptors` for parameters that have a default value provided.
- Update the generated code for VCTHs to produce an arguments object to the `InvokeCoreAsync` method that contains only the provided parameters

**Updates to the VCTH descriptor factory**

The VCTH descriptor contains a `RequiredAttributeDescriptor` for every parameter to the `InvokeAsync` method on the VC. When a parameter has a default value provided, we don't need to configure the parameter as a `RequiredAttribute` on the VCTH descriptor.

With this change in place, instances of the VCTH that don't contain the required attribute will still match with the VCTH. For example, the following VC:


```csharp
public class FooViewComponent : ViewComponent
{
    public IViewResult InvokeAsync(string foo, string bar = "default value")
    {
        return $"{foo} : {bar}";
    }
}
```

Would produce a VCTH descriptor that looks like this:

```
- ViewComponentTagHelper
  - RequiredAttributeDescriptor(propertyName = "foo")
  - BoundAttributeDescriptor(propertyName = "foo")
  - BoundAttributeDescriptor(propertyName = "bar")
```

And will match VCTH instances like:

```
<vc:foo foo="a-foo-value"></vc:foo>
<vc:foo foo="a-foo-value" bar="a-bar-value"></vc:foo>
```

But not VCTH instances that looks like:

```
<vc:foo bar="a-bar-value"></vc:foo>
<vc:foo></vc:foo>
```

All this can happen with very few changes to the tag helper matching logic that already exists.

**Update the generated code for VCTHs**

Presently, whenever a VCTH is encountered, generated code is produced that:

- Writes a class representing the view component which contains properties for each parameter provided to the `InvokeAsync` method and a `ProcessAsync` method that passes the class properties as arguments to `InvokeAsync`
- Instantiates an instance of the class above and sets class properties with their associated attributes

Even if the VCTH is matched to the VC successfully as a result of the changes above, the generated code will be inaccurate because null values will be passed for parameters that have default values. Instead, we want to construct an arguments object that only contains the parameters that were provided as attributes to the VCTH instance.

We do this by adding a new `ProcessInvokeAsyncArgs` that evaluates if each of the parameters was provided as an attribute to the VCTH instance and if so, sets its value in the arguments object.

```csharp
private Dictionary<string, object> ProcessInvokeAsyncArgs(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context)
{
    Dictionary<string, object> args = new();
    if (__context.AllAttributes.ContainsName("first-name"))
    {
        args[nameof(firstName)] = firstName;
    }
    return args;
}
```

The net effect is that we only pass set parameters as arguments to the method. For parameters that aren't passed as arguments, the default value will be used.
上级 df0feef8
......@@ -172,7 +172,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
foreach (var parameter in methodParameters)
{
if (GetIndexerValueTypeName(parameter) == null)
// HasExplicitDefaultValue is set on IParameterSymbol when a default value is passed
// in ala `int foo = 3`. This value can be used to determine the optionality of a parameter
// while ensuring that a default value has been set.
if (GetIndexerValueTypeName(parameter) == null && parameter.HasExplicitDefaultValue != true)
{
// Set required attributes only for non-indexer attributes. Indexer attributes can't be required attributes
// because there are two ways of setting values for the attribute.
......
......@@ -34,10 +34,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public string TagHelperProcessMethodName { get; set; } = "ProcessAsync";
public string TagHelperProcessInvokeAsyncArgsMethodName { get; set; } = "ProcessInvokeAsyncArgs";
public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext";
public string TagHelperContextVariableName { get; set; } = "__context";
public string TagHelperContextAttributesVariableName { get; set; } = "AllAttributes";
public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput";
public string TagHelperOutputVariableName { get; set; } = "__output";
......@@ -81,6 +85,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
// Add process method.
WriteProcessMethodString(context.CodeWriter, node.TagHelper);
// We pre-process the arguments passed to `InvokeAsync` to ensure that the
// provided markup attributes (in kebab-case) are matched to the associated
// properties in the VCTH class.
WriteProcessInvokeAsyncArgsMethodString(context.CodeWriter, node.TagHelper);
}
}
......@@ -158,13 +167,35 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
}
}
private void WriteProcessInvokeAsyncArgsMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
var methodReturnType = "Dictionary<string, object>";
using (writer.BuildMethodDeclaration(
"private",
methodReturnType,
TagHelperProcessInvokeAsyncArgsMethodName,
new Dictionary<string, string>() { { TagHelperContextTypeName, TagHelperContextVariableName } }))
{
writer.WriteStartAssignment($"{methodReturnType} args").WriteLine("new();");
for (var i = 0; i < tagHelper.BoundAttributes.Count; i++)
{
var attributeName = tagHelper.BoundAttributes[i].Name;
var parameterName = tagHelper.BoundAttributes[i].GetPropertyName();
writer.WriteLine($"if (__context.AllAttributes.ContainsName(\"{attributeName}\"))");
writer.WriteLine("{");
writer.CurrentIndent += writer.TabSize;
writer.WriteLine($"args[nameof({parameterName})] = {parameterName};");
writer.CurrentIndent -= writer.TabSize;
writer.WriteLine("}");
}
writer.WriteLine("return args;");
}
}
private string[] GetMethodParameters(TagHelperDescriptor tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
var methodParameters = new[] { $"\"{viewComponentName}\"", $"{TagHelperProcessInvokeAsyncArgsMethodName}({TagHelperContextVariableName})" };
return methodParameters;
}
......
......@@ -508,6 +508,54 @@ public class AllTagHelper : {typeof(TagHelper).FullName}
AssertLinePragmas(compiled.CodeDocument, designTime: false);
}
[Fact]
public void ViewComponentTagHelperOptionalParam_Runtime()
{
// Arrange
AddCSharpSyntaxTree($@"
using System;
public class OptionalTestViewComponent
{{
public string Invoke(bool showSecret = false)
{{
return showSecret ? ""what a secret"" : ""not a secret"";
}}
}}
public class OptionalTestWithParamViewComponent
{{
public string Invoke(string secret, bool showSecret = false)
{{
var isSecret = showSecret ? ""what a secret"" : ""not a secret"";
return isSecret + "" : "" + secret;
}}
}}
public class OptionalWithMultipleTypesViewComponent
{{
public string Invoke(
int age = 42,
double favoriteDecimal = 12.3,
char favoriteLetter = 'b',
DateTime? birthDate = null,
string anotherOne = null)
{{
birthDate = new DateTime(1979, 8, 23);
return age + "" : "" + favoriteDecimal + "" : "" + favoriteLetter + "" : "" + birthDate + "" : "" + anotherOne;
}}
}}
");
var projectItem = CreateProjectItemFromFile();
// Act
var compiled = CompileToAssembly(projectItem, designTime: false);
// Assert
AssertDocumentNodeMatchesBaseline(compiled.CodeDocument.GetDocumentIntermediateNode());
AssertCSharpDocumentMatchesBaseline(compiled.CodeDocument.GetCSharpDocument());
AssertLinePragmas(compiled.CodeDocument, designTime: false);
}
[Fact]
public void RazorPageWithNoLeadingPageDirective_Runtime()
{
......
@addTagHelper "*, AppCode"
<vc:optional-test></vc:optional-test>
<vc:optional-test show-secret="@true"></vc:optional-test>
<vc:optional-test-with-param secret="mysecret"></vc:optional-test-with-param>
<vc:optional-test-with-param secret="mysecret" show-secret="@true"></vc:optional-test-with-param>
<vc:optional-with-multiple-types></vc:optional-with-multiple-types>
<vc:optional-with-multiple-types age="12" favorite-decimal="10.8" favorite-letter="'a'"></vc:optional-with-multiple-types>
<vc:optional-with-multiple-types age="12" favorite-decimal="10.8"></vc:optional-with-multiple-types>
<vc:optional-with-multiple-types age="12" favorite-decimal="10.8" birth-date="DateTime.Now"></vc:optional-with-multiple-types>
<vc:optional-with-multiple-types age="12" favorite-decimal="10.8" birth-date="DateTime.Now"></vc:optional-with-multiple-types>
\ No newline at end of file
Document -
RazorCompiledItemAttribute -
NamespaceDeclaration - - AspNetCore
UsingDirective - (1:0,1 [14] ) - System
UsingDirective - (16:1,1 [34] ) - System.Collections.Generic
UsingDirective - (51:2,1 [19] ) - System.Linq
UsingDirective - (71:3,1 [30] ) - System.Threading.Tasks
UsingDirective - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc
UsingDirective - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingDirective - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures
RazorSourceChecksumAttribute -
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic> -
DefaultTagHelperRuntime -
FieldDeclaration - - private - global::AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalTestViewComponentTagHelper - __OptionalTestViewComponentTagHelper
FieldDeclaration - - private - global::AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalTestWithParamViewComponentTagHelper - __OptionalTestWithParamViewComponentTagHelper
FieldDeclaration - - private - global::AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalWithMultipleTypesViewComponentTagHelper - __OptionalWithMultipleTypesViewComponentTagHelper
MethodDeclaration - - public async override - global::System.Threading.Tasks.Task - ExecuteAsync
HtmlContent - (28:1,0 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (28:1,0 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (30:2,0 [37] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-test - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalTestViewComponentTagHelper
DefaultTagHelperExecute -
HtmlContent - (67:2,37 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (67:2,37 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (69:3,0 [57] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-test - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalTestViewComponentTagHelper
DefaultTagHelperProperty - (100:3,31 [5] ViewComponentTagHelperOptionalParam.cshtml) - show-secret - bool OptionalTestViewComponentTagHelper.showSecret - HtmlAttributeValueStyle.DoubleQuotes
CSharpExpression - (101:3,32 [4] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (101:3,32 [4] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - true
DefaultTagHelperExecute -
HtmlContent - (126:3,57 [4] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (126:3,57 [4] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n\n
TagHelper - (130:5,0 [77] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-test-with-param - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalTestWithParamViewComponentTagHelper
DefaultTagHelperProperty - (167:5,37 [8] ViewComponentTagHelperOptionalParam.cshtml) - secret - string OptionalTestWithParamViewComponentTagHelper.secret - HtmlAttributeValueStyle.DoubleQuotes
HtmlContent - (167:5,37 [8] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (167:5,37 [8] ViewComponentTagHelperOptionalParam.cshtml) - Html - mysecret
DefaultTagHelperExecute -
HtmlContent - (207:5,77 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (207:5,77 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (209:6,0 [97] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-test-with-param - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalTestWithParamViewComponentTagHelper
DefaultTagHelperProperty - (246:6,37 [8] ViewComponentTagHelperOptionalParam.cshtml) - secret - string OptionalTestWithParamViewComponentTagHelper.secret - HtmlAttributeValueStyle.DoubleQuotes
HtmlContent - (246:6,37 [8] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (246:6,37 [8] ViewComponentTagHelperOptionalParam.cshtml) - Html - mysecret
DefaultTagHelperProperty - (269:6,60 [5] ViewComponentTagHelperOptionalParam.cshtml) - show-secret - bool OptionalTestWithParamViewComponentTagHelper.showSecret - HtmlAttributeValueStyle.DoubleQuotes
CSharpExpression - (270:6,61 [4] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (270:6,61 [4] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - true
DefaultTagHelperExecute -
HtmlContent - (306:6,97 [4] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (306:6,97 [4] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n\n
TagHelper - (310:8,0 [67] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-with-multiple-types - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalWithMultipleTypesViewComponentTagHelper
DefaultTagHelperExecute -
HtmlContent - (377:8,67 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (377:8,67 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (379:9,0 [122] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-with-multiple-types - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalWithMultipleTypesViewComponentTagHelper
DefaultTagHelperProperty - (417:9,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - age - int OptionalWithMultipleTypesViewComponentTagHelper.age - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (417:9,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 12
DefaultTagHelperProperty - (439:9,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - favorite-decimal - double OptionalWithMultipleTypesViewComponentTagHelper.favoriteDecimal - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (439:9,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 10.8
DefaultTagHelperProperty - (462:9,83 [3] ViewComponentTagHelperOptionalParam.cshtml) - favorite-letter - char OptionalWithMultipleTypesViewComponentTagHelper.favoriteLetter - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (462:9,83 [3] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 'a'
DefaultTagHelperExecute -
HtmlContent - (501:9,122 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (501:9,122 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (503:10,0 [100] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-with-multiple-types - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalWithMultipleTypesViewComponentTagHelper
DefaultTagHelperProperty - (541:10,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - age - int OptionalWithMultipleTypesViewComponentTagHelper.age - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (541:10,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 12
DefaultTagHelperProperty - (563:10,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - favorite-decimal - double OptionalWithMultipleTypesViewComponentTagHelper.favoriteDecimal - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (563:10,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 10.8
DefaultTagHelperExecute -
HtmlContent - (603:10,100 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (603:10,100 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (605:11,0 [126] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-with-multiple-types - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalWithMultipleTypesViewComponentTagHelper
DefaultTagHelperProperty - (643:11,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - age - int OptionalWithMultipleTypesViewComponentTagHelper.age - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (643:11,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 12
DefaultTagHelperProperty - (665:11,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - favorite-decimal - double OptionalWithMultipleTypesViewComponentTagHelper.favoriteDecimal - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (665:11,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 10.8
DefaultTagHelperProperty - (683:11,78 [12] ViewComponentTagHelperOptionalParam.cshtml) - birth-date - System.DateTime? OptionalWithMultipleTypesViewComponentTagHelper.birthDate - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (683:11,78 [12] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - DateTime.Now
DefaultTagHelperExecute -
HtmlContent - (731:11,126 [2] ViewComponentTagHelperOptionalParam.cshtml)
LazyIntermediateToken - (731:11,126 [2] ViewComponentTagHelperOptionalParam.cshtml) - Html - \n
TagHelper - (733:12,0 [126] ViewComponentTagHelperOptionalParam.cshtml) - vc:optional-with-multiple-types - TagMode.StartTagAndEndTag
DefaultTagHelperBody -
DefaultTagHelperCreate - - AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_ViewComponentTagHelperOptionalParam.__Generated__OptionalWithMultipleTypesViewComponentTagHelper
DefaultTagHelperProperty - (771:12,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - age - int OptionalWithMultipleTypesViewComponentTagHelper.age - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (771:12,38 [2] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 12
DefaultTagHelperProperty - (793:12,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - favorite-decimal - double OptionalWithMultipleTypesViewComponentTagHelper.favoriteDecimal - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (793:12,60 [4] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - 10.8
DefaultTagHelperProperty - (811:12,78 [12] ViewComponentTagHelperOptionalParam.cshtml) - birth-date - System.DateTime? OptionalWithMultipleTypesViewComponentTagHelper.birthDate - HtmlAttributeValueStyle.DoubleQuotes
LazyIntermediateToken - (811:12,78 [12] ViewComponentTagHelperOptionalParam.cshtml) - CSharp - DateTime.Now
DefaultTagHelperExecute -
Inject -
Inject -
Inject -
Inject -
Inject -
ViewComponentTagHelper -
ViewComponentTagHelper -
ViewComponentTagHelper -
......@@ -86,10 +86,19 @@ global::System.Object __typeHelper = "*, AppCode";
public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput __output)
{
(__helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
var __helperContent = await __helper.InvokeAsync("Test", new { firstName });
var __helperContent = await __helper.InvokeAsync("Test", ProcessInvokeAsyncArgs(__context));
__output.TagName = null;
__output.Content.SetHtmlContent(__helperContent);
}
private Dictionary<string, object> ProcessInvokeAsyncArgs(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context)
{
Dictionary<string, object> args = new();
if (__context.AllAttributes.ContainsName("first-name"))
{
args[nameof(firstName)] = firstName;
}
return args;
}
}
}
}
......
......@@ -73,8 +73,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
rule
.RequireTagName("vc:various-parameter")
.RequireAttributeDescriptor(attribute => attribute.Name("test-enum"))
.RequireAttributeDescriptor(attribute => attribute.Name("test-string"))
.RequireAttributeDescriptor(attribute => attribute.Name("baz")))
.RequireAttributeDescriptor(attribute => attribute.Name("test-string")))
.BoundAttributeDescriptor(attribute =>
attribute
.Name("test-enum")
......
......@@ -52,10 +52,19 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput __output)
{
(__helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
var __helperContent = await __helper.InvokeAsync(""TagCloud"", new { Foo });
var __helperContent = await __helper.InvokeAsync(""TagCloud"", ProcessInvokeAsyncArgs(__context));
__output.TagName = null;
__output.Content.SetHtmlContent(__helperContent);
}
private Dictionary<string, object> ProcessInvokeAsyncArgs(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context)
{
Dictionary<string, object> args = new();
if (__context.AllAttributes.ContainsName(""Foo""))
{
args[nameof(Foo)] = Foo;
}
return args;
}
}
",
csharp,
......@@ -107,10 +116,19 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput __output)
{
(__helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
var __helperContent = await __helper.InvokeAsync(""TagCloud"", new { Tags });
var __helperContent = await __helper.InvokeAsync(""TagCloud"", ProcessInvokeAsyncArgs(__context));
__output.TagName = null;
__output.Content.SetHtmlContent(__helperContent);
}
private Dictionary<string, object> ProcessInvokeAsyncArgs(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext __context)
{
Dictionary<string, object> args = new();
if (__context.AllAttributes.ContainsName(""Foo""))
{
args[nameof(Tags)] = Tags;
}
return args;
}
}
",
csharp,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册