Skip to content
This repository was archived by the owner on Dec 19, 2018. It is now read-only.

Commit cf7f3b1

Browse files
author
N. Taylor Mullen
committed
Added CodeGen for TagHelper content mode redesign.
- Modified the CSharpTagHelperCodeRenderer to understand a single line of TagHelper rendering (instead of doing different things based on ContentBehavior). - Modified existing CodeGen output to reflect new content changes. #221
1 parent fd67fbb commit cf7f3b1

File tree

11 files changed

+712
-319
lines changed

11 files changed

+712
-319
lines changed

src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs

Lines changed: 102 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public void RenderTagHelper(TagHelperChunk chunk)
5858
{
5959
var tagHelperDescriptors = chunk.Descriptors;
6060

61-
RenderBeginTagHelperScope(chunk.TagName);
61+
RenderBeginTagHelperScope(chunk.TagName, chunk.Children);
6262

6363
RenderTagHelpersCreation(chunk);
6464

@@ -71,11 +71,15 @@ public void RenderTagHelper(TagHelperChunk chunk)
7171

7272
RenderUnboundHTMLAttributes(unboundHTMLAttributes);
7373

74-
// TODO: Modify code generation to handle all content modes
75-
//RenderRunTagHelpers(bufferedBody: false);
76-
//RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
77-
//RenderTagHelperBody(chunk.Children, bufferBody: false);
78-
//RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
74+
RenderRunTagHelpers();
75+
76+
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
77+
RenderTagOutput(_tagHelperContext.OutputGeneratePreContentMethodName);
78+
79+
RenderTagHelperContent();
80+
81+
RenderTagOutput(_tagHelperContext.OutputGeneratePostContentMethodName);
82+
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
7983

8084
RenderEndTagHelpersScope();
8185
}
@@ -85,11 +89,13 @@ internal static string GetVariableName(TagHelperDescriptor descriptor)
8589
return "__" + descriptor.TypeName.Replace('.', '_');
8690
}
8791

88-
private void RenderBeginTagHelperScope(string tagName)
92+
private void RenderBeginTagHelperScope(string tagName, IList<Chunk> children)
8993
{
9094
// Scopes/execution contexts are a runtime feature.
9195
if (_designTimeMode)
9296
{
97+
// Render all of the tag helper children inline for intellisense.
98+
_bodyVisitor.Accept(children);
9399
return;
94100
}
95101

@@ -104,6 +110,30 @@ private void RenderBeginTagHelperScope(string tagName)
104110
_writer.WriteStringLiteral(tagName)
105111
.WriteParameterSeparator()
106112
.WriteStringLiteral(GenerateUniqueId())
113+
.WriteParameterSeparator();
114+
115+
// We remove the target writer so TagHelper authors can retrieve content.
116+
var oldWriter = _context.TargetWriterName;
117+
_context.TargetWriterName = null;
118+
119+
// Disabling instrumentation inside TagHelper bodies since we never know if it's accurate
120+
var oldInstrumentation = _context.Host.EnableInstrumentation;
121+
_context.Host.EnableInstrumentation = false;
122+
123+
using (_writer.BuildAsyncLambda(endLine: false))
124+
{
125+
// Render all of the tag helper children.
126+
_bodyVisitor.Accept(children);
127+
}
128+
129+
_context.Host.EnableInstrumentation = oldInstrumentation;
130+
131+
_context.TargetWriterName = oldWriter;
132+
133+
_writer.WriteParameterSeparator()
134+
.Write(_tagHelperContext.StartWritingScopeMethodName)
135+
.WriteParameterSeparator()
136+
.Write(_tagHelperContext.EndWritingScopeMethodName)
107137
.WriteEndMethodInvocation();
108138
}
109139

@@ -302,18 +332,72 @@ private void RenderUnboundHTMLAttributes(IEnumerable<KeyValuePair<string, Chunk>
302332
}
303333
}
304334

305-
private void RenderTagHelperBody(IList<Chunk> children, bool bufferBody)
335+
private void RenderTagHelperContent()
306336
{
307-
// If we want to buffer the body we need to create a writing scope to capture the body content.
308-
if (bufferBody)
337+
// Rendering output is a runtime feature.
338+
if (_designTimeMode)
309339
{
310-
// Render all of the tag helper children in a buffered writing scope.
311-
BuildBufferedWritingScope(children);
340+
return;
312341
}
313-
else
342+
343+
_writer.Write("if (")
344+
.Write(ExecutionContextVariableName)
345+
.Write(".")
346+
.Write(_tagHelperContext.ExecutionContextOutputPropertyName)
347+
.Write(".")
348+
.Write(_tagHelperContext.OutputContentSetPropertyName)
349+
.WriteLine(")");
350+
351+
// Render the body of the if statement, at this point in the codegen the TagHelperOutput's Content was set
352+
// so we should just render its Content, no need to forcefully execute the child content.
353+
using (_writer.BuildScope())
314354
{
315-
// Render all of the tag helper children.
316-
_bodyVisitor.Accept(children);
355+
RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
356+
}
357+
358+
_writer.Write("else if (")
359+
.Write(ExecutionContextVariableName)
360+
.Write(".")
361+
.Write(_tagHelperContext.ExecutionContextChildContentRetrievedPropertyName)
362+
.WriteLine(")");
363+
364+
// Render the body of the else if statement, at this point in the codegen the GetChildContentAsync method
365+
// was invoked but the TagHelperOutput's Content was not set. Call into GetChildContentAsync to retrieve
366+
// the cached value of the content so we don't execute the child content twice.
367+
using (_writer.BuildScope())
368+
{
369+
CSharpCodeVisitor.RenderPreWriteStart(_writer, _context);
370+
371+
_writer.WriteInstanceMethodInvocation(ExecutionContextVariableName,
372+
_tagHelperContext.ExecutionContextGetChildContentAsyncMethodName,
373+
endLine: false);
374+
375+
_writer.Write(".Result")
376+
.WriteEndMethodInvocation();
377+
}
378+
379+
_writer.WriteLine("else");
380+
381+
// Render the body of the else statement, at this point in the codegen the GetChildContentAsync method
382+
// was not invoked and the TagHelperOutput's Content was not set. Call into ExecuteChildContentAsync to
383+
// to execute and render child content.
384+
using (_writer.BuildScope())
385+
{
386+
if (!string.IsNullOrEmpty(_context.TargetWriterName))
387+
{
388+
_writer.WriteMethodInvocation(_tagHelperContext.StartWritingScopeMethodName, _context.TargetWriterName);
389+
}
390+
391+
_writer.WriteInstanceMethodInvocation(
392+
ExecutionContextVariableName,
393+
_tagHelperContext.ExecutionContextExecuteChildContentAsyncMethodName,
394+
endLine: false);
395+
_writer.WriteLine(".Wait();");
396+
397+
if (!string.IsNullOrEmpty(_context.TargetWriterName))
398+
{
399+
_writer.WriteMethodInvocation(_tagHelperContext.EndWritingScopeMethodName);
400+
}
317401
}
318402
}
319403

@@ -348,7 +432,7 @@ private void RenderTagOutput(string tagOutputMethodName)
348432
.WriteEndMethodInvocation();
349433
}
350434

351-
private void RenderRunTagHelpers(bool bufferedBody)
435+
private void RenderRunTagHelpers()
352436
{
353437
// No need to run anything in design time mode.
354438
if (_designTimeMode)
@@ -362,15 +446,9 @@ private void RenderRunTagHelpers(bool bufferedBody)
362446
.Write(" = ")
363447
.WriteStartInstanceMethodInvocation(RunnerVariableName,
364448
_tagHelperContext.RunnerRunAsyncMethodName);
365-
_writer.Write(ExecutionContextVariableName);
366-
367-
if (bufferedBody)
368-
{
369-
_writer.WriteParameterSeparator()
370-
.Write(StringValueBufferVariableName);
371-
}
372449

373-
_writer.WriteEndMethodInvocation(endLine: false)
450+
_writer.Write(ExecutionContextVariableName)
451+
.WriteEndMethodInvocation(endLine: false)
374452
.WriteLine(".Result;");
375453
}
376454

src/Microsoft.AspNet.Razor/Generator/GeneratedTagHelperContext.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public GeneratedTagHelperContext()
2323
OutputGenerateContentMethodName = "GenerateContent";
2424
OutputGeneratePostContentMethodName = "GeneratePostContent";
2525
OutputGenerateEndTagMethodName = "GenerateEndTag";
26+
ExecutionContextChildContentRetrievedPropertyName = "ChildContentRetrieved";
2627
ExecutionContextExecuteChildContentAsyncMethodName = "ExecuteChildContentAsync";
28+
ExecutionContextGetChildContentAsyncMethodName = "GetChildContentAsync";
2729
ExecutionContextAddMethodName = "Add";
2830
ExecutionContextAddTagHelperAttributeMethodName = "AddTagHelperAttribute";
2931
ExecutionContextAddHtmlAttributeMethodName = "AddHtmlAttribute";
@@ -85,11 +87,23 @@ public GeneratedTagHelperContext()
8587
/// </summary>
8688
public string OutputGenerateEndTagMethodName { get; set; }
8789

90+
/// <summary>
91+
/// The name of the <see cref="ExecutionContextTypeName"/> property that indicates if child content has
92+
/// been retrieved
93+
/// </summary>
94+
public string ExecutionContextChildContentRetrievedPropertyName { get; set; }
95+
8896
/// <summary>
8997
/// The name of the <see cref="ExecutionContextTypeName"/> method used to execute tag helper child content.
9098
/// </summary>
9199
public string ExecutionContextExecuteChildContentAsyncMethodName { get; set; }
92100

101+
/// <summary>
102+
/// The name of the <see cref="ExecutionContextTypeName"/> method used to execute and retrieve tag helper
103+
/// child content.
104+
/// </summary>
105+
public string ExecutionContextGetChildContentAsyncMethodName { get; set; }
106+
93107
/// <summary>
94108
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add tag helper attributes.
95109
/// </summary>

test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingTest.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ public static TheoryData DesignTimeTagHelperTestData
174174
BuildLineMapping(documentAbsoluteIndex: 189,
175175
documentLineIndex: 6,
176176
documentCharacterOffsetIndex: 40,
177-
generatedAbsoluteIndex: 1599,
178-
generatedLineIndex: 44,
177+
generatedAbsoluteIndex: 1540,
178+
generatedLineIndex: 43,
179179
generatedCharacterOffsetIndex: 40,
180180
contentLength: 4)
181181
}
@@ -188,17 +188,17 @@ public static TheoryData DesignTimeTagHelperTestData
188188
{
189189
BuildLineMapping(14, 0, 479, 15, 14, 11),
190190
BuildLineMapping(30, 2, 1, 995, 35, 0, 48),
191-
BuildLineMapping(157, 7, 32, 1177, 45, 6, 12),
192-
BuildLineMapping(205, 9, 1260, 50, 0, 12),
193-
BuildLineMapping(218, 9, 13, 1356, 56, 12, 27),
194-
BuildLineMapping(346, 12, 1754, 68, 0, 48),
195-
BuildLineMapping(440, 15, 46, 2004, 78, 6, 8),
196-
BuildLineMapping(457, 15, 63, 2267, 85, 40, 4),
197-
BuildLineMapping(501, 16, 31, 2384, 88, 6, 30),
198-
BuildLineMapping(568, 17, 30, 2733, 97, 0, 10),
199-
BuildLineMapping(601, 17, 63, 2815, 103, 0, 8),
200-
BuildLineMapping(632, 17, 94, 2895, 109, 0, 1),
201-
BuildLineMapping(639, 18, 3149, 118, 0, 15),
191+
BuildLineMapping(205, 9, 1113, 44, 0, 12),
192+
BuildLineMapping(218, 9, 13, 1209, 50, 12, 27),
193+
BuildLineMapping(346, 12, 1607, 62, 0, 48),
194+
BuildLineMapping(440, 15, 46, 1798, 71, 6, 8),
195+
BuildLineMapping(457, 15, 63, 2061, 78, 40, 4),
196+
BuildLineMapping(501, 16, 31, 2237, 82, 6, 30),
197+
BuildLineMapping(568, 17, 30, 2586, 91, 0, 10),
198+
BuildLineMapping(601, 17, 63, 2668, 97, 0, 8),
199+
BuildLineMapping(632, 17, 94, 2748, 103, 0, 1),
200+
BuildLineMapping(639, 18, 3002, 112, 0, 15),
201+
BuildLineMapping(157, 7, 32, 3151, 119, 6, 12),
202202
BuildLineMapping(680, 21, 3234, 124, 0, 1)
203203
}
204204
}

0 commit comments

Comments
 (0)