| File: Mvc\ViewComponentTagHelperTargetExtensionBase.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions; internal abstract class ViewComponentTagHelperTargetExtensionBase : IViewComponentTagHelperTargetExtension { private static readonly ImmutableArray<MethodParameter> s_constructorParameters = [ new("helper", ViewComponentsApi.IViewComponentHelper.GloballyQualifiedTypeName) ]; private static readonly string s_taskTypeName = $"global::{typeof(Task).FullName}"; private ImmutableArray<MethodParameter> _processMethodParameters; public ImmutableArray<MethodParameter> ProcessMethodParameters { get { if (_processMethodParameters.IsDefault) { ImmutableInterlocked.InterlockedInitialize(ref _processMethodParameters, [ new(TagHelperContextVariableName, ViewComponentsApi.TagHelperContext.FullTypeName), new(TagHelperOutputVariableName, ViewComponentsApi.TagHelperOutput.FullTypeName) ]); } return _processMethodParameters; } } private static readonly ImmutableArray<string> s_contextualizeArguments = [ViewComponentsApi.ViewContextPropertyName]; protected abstract string TagHelperContentVariableName { get; } protected abstract string TagHelperContextVariableName { get; } protected abstract string TagHelperOutputVariableName { get; } protected abstract string ViewComponentHelperVariableName { get; } public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node) { // Add target element. WriteTargetElementString(context.CodeWriter, node.TagHelper); // Initialize declaration. using (context.CodeWriter.BuildClassDeclaration( CommonModifiers.Public, node.ClassName, new BaseTypeWithModel(ViewComponentsApi.TagHelper.FullTypeName), interfaces: default, typeParameters: default, context)) { // Add view component helper. context.CodeWriter.WriteFieldDeclaration( CommonModifiers.PrivateReadOnly, ViewComponentsApi.IViewComponentHelper.GloballyQualifiedTypeName, ViewComponentHelperVariableName); // Add constructor. WriteConstructorString(context.CodeWriter, node.ClassName); // Add attributes. WriteAttributeDeclarations(context.CodeWriter, node.TagHelper); // Add process method. WriteProcessMethodString(context.CodeWriter, node.TagHelper); WriteAdditionalMembers(context, node); } } protected virtual void WriteAdditionalMembers(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node) { } protected abstract ImmutableArray<string> GetInvokeArguments(TagHelperDescriptor tagHelper); private static void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper) { Debug.Assert(tagHelper.TagMatchingRules.Length == 1); var rule = tagHelper.TagMatchingRules[0]; writer.Write("[") .WriteStartMethodInvocation(ViewComponentsApi.HtmlTargetElementAttribute.FullTypeName) .WriteStringLiteral(rule.TagName) .WriteLine(")]"); } private void WriteConstructorString(CodeWriter writer, string className) { using (writer.BuildConstructorDeclaration(CommonModifiers.Public, className, s_constructorParameters)) { writer.WriteStartAssignment(ViewComponentHelperVariableName) .WriteLine("helper;"); } } private static void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper) { writer.Write("[") .Write(ViewComponentsApi.HtmlAttributeNotBoundAttribute.FullTypeName) .WriteParameterSeparator() .Write(ViewComponentsApi.ViewContextAttribute.GloballyQualifiedTypeName) .WriteLine("]"); writer.WriteAutoPropertyDeclaration( CommonModifiers.Public, ViewComponentsApi.ViewContext.GloballyQualifiedTypeName, ViewComponentsApi.ViewContextPropertyName); foreach (var attribute in tagHelper.BoundAttributes) { writer.WriteAutoPropertyDeclaration( CommonModifiers.Public, attribute.TypeName, attribute.PropertyName); if (attribute.IndexerTypeName != null) { writer.Write(" = ") .WriteStartNewObject(attribute.TypeName) .WriteEndMethodInvocation(); } } } private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper) { using (writer.BuildMethodDeclaration( CommonModifiers.PublicOverrideAsync, returnType: s_taskTypeName, ViewComponentsApi.ProcessAsyncMethodName, parameters: ProcessMethodParameters)) { writer.WriteMethodInvocation( $"({ViewComponentHelperVariableName} as {ViewComponentsApi.IViewContextAware.GloballyQualifiedTypeName})?.{ViewComponentsApi.IViewContextAware.ContextualizeMethodName}", s_contextualizeArguments); var invokeArguments = GetInvokeArguments(tagHelper); writer.Write("var ") .WriteStartAssignment(TagHelperContentVariableName) .Write("await ") .WriteMethodInvocation($"{ViewComponentHelperVariableName}.{ViewComponentsApi.IViewComponentHelper.InvokeMethodName}", invokeArguments); writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{ViewComponentsApi.TagHelperOutput.TagNamePropertyName}") .WriteLine("null;"); writer.WriteMethodInvocation( $"{TagHelperOutputVariableName}.{ViewComponentsApi.TagHelperOutput.ContentPropertyName}.{ViewComponentsApi.TagHelperOutput.ContentSetMethodName}", arguments: [TagHelperContentVariableName]); } } }