public void WriteSection(CodeRenderingContext context, SectionIntermediateNode node) { context.CodeWriter .WriteStartMethodInvocation(SectionMethodName) .Write("\"") .Write(node.SectionName) .Write("\", "); if (context.Options.DesignTime) { using (context.CodeWriter.BuildAsyncLambda(DefaultWriterName)) { context.RenderChildren(node); } } else { using (context.CodeWriter.BuildAsyncLambda()) { context.RenderChildren(node); } } context.CodeWriter.WriteEndMethodInvocation(endLine: true); }
public void WriteTagHelperBody(CodeRenderingContext context, DefaultTagHelperBodyIntermediateNode node) { if (context.Parent as TagHelperIntermediateNode == null) { var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode)); throw new InvalidOperationException(message); } if (context.Options.DesignTime) { context.RenderChildren(node); } else { // Call into the tag helper scope manager to start a new tag helper scope. // Also capture the value as the current execution context. context.CodeWriter .WriteStartAssignment(ExecutionContextVariableName) .WriteStartInstanceMethodInvocation( ScopeManagerVariableName, ScopeManagerBeginMethodName); // Assign a unique ID for this instance of the source HTML tag. This must be unique // per call site, e.g. if the tag is on the view twice, there should be two IDs. var uniqueId = (string)context.Items[CodeRenderingContext.SuppressUniqueIds]; if (uniqueId == null) { uniqueId = GetDeterministicId(context); } context.CodeWriter.WriteStringLiteral(node.TagName) .WriteParameterSeparator() .Write(TagModeTypeName) .Write(".") .Write(node.TagMode.ToString()) .WriteParameterSeparator() .WriteStringLiteral(uniqueId) .WriteParameterSeparator(); using (context.CodeWriter.BuildAsyncLambda()) { // We remove and redirect writers so TagHelper authors can retrieve content. context.RenderChildren(node, new RuntimeNodeWriter()); } context.CodeWriter.WriteEndMethodInvocation(); } }
public void WriteSection(CodeRenderingContext context, SectionIntermediateNode node) { // Quirk Alert! // // In 1.0.0 Razor/MVC the define section method took a parameter for a TextWriter // that would be used for all of the output in the section. We simplified this API for // 2.0.0 of MVC, but our design time codegen still needs to target 1.0.0. // // So the workaround is MVC 2.0.0 will define these methods with the TextWriter, but // that method is never called. We still generate the call *with* the TextWriter for // design time, at least until we have multi-targeting. var writerName = context.Options.DesignTime ? DefaultWriterName : string.Empty; context.CodeWriter .WriteStartMethodInvocation(SectionMethodName) .Write("\"") .Write(node.SectionName) .Write("\", "); using (context.CodeWriter.BuildAsyncLambda(writerName)) { context.RenderChildren(node); } context.CodeWriter.WriteEndMethodInvocation(endLine: true); }
public override void WriteMarkupElement(CodeRenderingContext context, MarkupElementIntermediateNode node) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (node == null) { throw new ArgumentNullException(nameof(node)); } context.RenderChildren(node); }
public void WriteTemplate(CodeRenderingContext context, TemplateIntermediateNode node) { const string ItemParameterName = "item"; const string TemplateWriterName = "__razor_template_writer"; context.CodeWriter .Write(ItemParameterName).Write(" => ") .WriteStartNewObject(TemplateTypeName); using (context.CodeWriter.BuildAsyncLambda(TemplateWriterName)) { context.NodeWriter.BeginWriterScope(context, TemplateWriterName); context.RenderChildren(node); context.NodeWriter.EndWriterScope(context); } context.CodeWriter.WriteEndMethodInvocation(endLine: false); }
public void WriteTagHelperProperty(CodeRenderingContext context, DefaultTagHelperPropertyIntermediateNode node) { var tagHelperNode = context.Parent as TagHelperIntermediateNode; if (context.Parent == null) { var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode)); throw new InvalidOperationException(message); } if (!context.Options.DesignTime) { // Ensure that the property we're trying to set has initialized its dictionary bound properties. if (node.IsIndexerNameMatch && object.ReferenceEquals(FindFirstUseOfIndexer(tagHelperNode, node), node)) { // Throw a reasonable Exception at runtime if the dictionary property is null. context.CodeWriter .Write("if (") .Write(node.FieldName) .Write(".") .Write(node.PropertyName) .WriteLine(" == null)"); using (context.CodeWriter.BuildScope()) { // System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName // of InvalidOperationException type. context.CodeWriter .Write("throw ") .WriteStartNewObject(nameof(InvalidOperationException)) .WriteStartMethodInvocation(FormatInvalidIndexerAssignmentMethodName) .WriteStringLiteral(node.AttributeName) .WriteParameterSeparator() .WriteStringLiteral(node.TagHelper.GetTypeName()) .WriteParameterSeparator() .WriteStringLiteral(node.PropertyName) .WriteEndMethodInvocation(endLine: false) // End of method call .WriteEndMethodInvocation(); // End of new expression / throw statement } } } // If this is not the first use of the attribute value, we need to evaluate the expression and assign it to // the tag helper property. // // Otherwise, the value has already been computed and assigned to another tag helper. We just need to // copy from that tag helper to this one. // // This is important because we can't evaluate the expression twice due to side-effects. var firstUseOfAttribute = FindFirstUseOfAttribute(tagHelperNode, node); if (!object.ReferenceEquals(firstUseOfAttribute, node)) { // If we get here, this value has already been used. We just need to copy the value. context.CodeWriter .WriteStartAssignment(GetPropertyAccessor(node)) .Write(GetPropertyAccessor(firstUseOfAttribute)) .WriteLine(";"); return; } // If we get there, this is the first time seeing this property so we need to evaluate the expression. if (node.BoundAttribute.ExpectsStringValue(node.AttributeName)) { if (context.Options.DesignTime) { context.RenderChildren(node); context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node)); if (node.Children.Count == 1 && node.Children.First() is HtmlContentIntermediateNode htmlNode) { var content = GetContent(htmlNode); context.CodeWriter.WriteStringLiteral(content); } else { context.CodeWriter.Write("string.Empty"); } context.CodeWriter.WriteLine(";"); } else { context.CodeWriter.WriteMethodInvocation(BeginWriteTagHelperAttributeMethodName); context.RenderChildren(node, new LiteralRuntimeNodeWriter()); context.CodeWriter .WriteStartAssignment(StringValueBufferVariableName) .WriteMethodInvocation(EndWriteTagHelperAttributeMethodName) .WriteStartAssignment(GetPropertyAccessor(node)) .Write(StringValueBufferVariableName) .WriteLine(";"); } } else { if (context.Options.DesignTime) { var firstMappedChild = node.Children.FirstOrDefault(child => child.Source != null) as IntermediateNode; var valueStart = firstMappedChild?.Source; using (context.CodeWriter.BuildLinePragma(node.Source, context)) { var accessor = GetPropertyAccessor(node); var assignmentPrefixLength = accessor.Length + " = ".Length; if (node.BoundAttribute.IsEnum && node.Children.Count == 1 && node.Children.First() is IntermediateToken token && token.IsCSharp) { assignmentPrefixLength += $"global::{node.BoundAttribute.TypeName}.".Length; if (valueStart != null) { context.CodeWriter.WritePadding(assignmentPrefixLength, node.Source, context); } context.CodeWriter .WriteStartAssignment(accessor) .Write("global::") .Write(node.BoundAttribute.TypeName) .Write("."); } else { if (valueStart != null) { context.CodeWriter.WritePadding(assignmentPrefixLength, node.Source, context); } context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node)); } if (node.Children.Count == 0 && node.AttributeStructure == AttributeStructure.Minimized && node.BoundAttribute.ExpectsBooleanValue(node.AttributeName)) { // If this is a minimized boolean attribute, set the value to true. context.CodeWriter.Write("true"); } else { RenderTagHelperAttributeInline(context, node, node.Source); } context.CodeWriter.WriteLine(";"); } }
public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, DefaultTagHelperHtmlAttributeIntermediateNode node) { if (context.Parent as TagHelperIntermediateNode == null) { var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode)); throw new InvalidOperationException(message); } if (context.Options.DesignTime) { context.RenderChildren(node); } else { var attributeValueStyleParameter = $"{HtmlAttributeValueStyleTypeName}.{node.AttributeStructure}"; var isConditionalAttributeValue = node.Children.Any( child => child is CSharpExpressionAttributeValueIntermediateNode || child is CSharpCodeAttributeValueIntermediateNode); // All simple text and minimized attributes will be pre-allocated. if (isConditionalAttributeValue) { // Dynamic attribute value should be run through the conditional attribute removal system. It's // unbound and contains C#. // TagHelper attribute rendering is buffered by default. We do not want to write to the current // writer. var valuePieceCount = node.Children.Count( child => child is HtmlAttributeValueIntermediateNode || child is CSharpExpressionAttributeValueIntermediateNode || child is CSharpCodeAttributeValueIntermediateNode || child is ExtensionIntermediateNode); context.CodeWriter .WriteStartMethodInvocation(BeginAddHtmlAttributeValuesMethodName) .Write(ExecutionContextVariableName) .WriteParameterSeparator() .WriteStringLiteral(node.AttributeName) .WriteParameterSeparator() .Write(valuePieceCount.ToString(CultureInfo.InvariantCulture)) .WriteParameterSeparator() .Write(attributeValueStyleParameter) .WriteEndMethodInvocation(); context.RenderChildren(node, new TagHelperHtmlAttributeRuntimeNodeWriter()); context.CodeWriter .WriteMethodInvocation( EndAddHtmlAttributeValuesMethodName, ExecutionContextVariableName); } else { // This is a data-* attribute which includes C#. Do not perform the conditional attribute removal or // other special cases used when IsDynamicAttributeValue(). But the attribute must still be buffered to // determine its final value. // Attribute value is not plain text, must be buffered to determine its final value. context.CodeWriter.WriteMethodInvocation(BeginWriteTagHelperAttributeMethodName); // We're building a writing scope around the provided chunks which captures everything written from the // page. Therefore, we do not want to write to any other buffer since we're using the pages buffer to // ensure we capture all content that's written, directly or indirectly. context.RenderChildren(node, new RuntimeNodeWriter()); context.CodeWriter .WriteStartAssignment(StringValueBufferVariableName) .WriteMethodInvocation(EndWriteTagHelperAttributeMethodName) .WriteStartInstanceMethodInvocation( ExecutionContextVariableName, ExecutionContextAddHtmlAttributeMethodName) .WriteStringLiteral(node.AttributeName) .WriteParameterSeparator() .WriteStartMethodInvocation(MarkAsHtmlEncodedMethodName) .Write(StringValueBufferVariableName) .WriteEndMethodInvocation(endLine: false) .WriteParameterSeparator() .Write(attributeValueStyleParameter) .WriteEndMethodInvocation(); } } }