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

Commit 5d92c94

Browse files
author
NTaylorMullen
committed
Add ModelExpression code generation.
- Sealed the ModelExpression. - We use the stringified version of the ModelExpression type name to detect ModelExpression properties on TagHelpers. This is so the MvcRazorHost can work in tooling and in runtime. - Created a GeneratedTagHelperAttributeContext to represent the specific stringified versions of the ModelExpression assets. - Created an MvcTagHelperAttributeValueCodeRenderer to modify rendering of ModelExpression properties. #1241
1 parent 246ac5a commit 5d92c94

File tree

5 files changed

+122
-2
lines changed

5 files changed

+122
-2
lines changed

src/Microsoft.AspNet.Mvc.Core/Rendering/ModelExpression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
1010
/// <summary>
1111
/// Describes an <see cref="System.Linq.Expressions.Expression"/> passed to a tag helper.
1212
/// </summary>
13-
public class ModelExpression
13+
public sealed class ModelExpression
1414
{
1515
/// <summary>
1616
/// Initializes a new instance of the <see cref="ModelExpression"/> class.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
5+
6+
namespace Microsoft.AspNet.Mvc.Razor
7+
{
8+
/// <summary>
9+
/// Contains information for the <see cref="ITagHelper"/> attribute code generation process.
10+
/// </summary>
11+
public class GeneratedTagHelperAttributeContext
12+
{
13+
/// <summary>
14+
/// String representation of the model expression type.
15+
/// </summary>
16+
public string ModelExpressionTypeName { get; set; }
17+
18+
/// <summary>
19+
/// String representation of a method to create model expression types.
20+
/// </summary>
21+
public string CreateModelExpressionMethodName { get; set; }
22+
}
23+
}

src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeBuilder.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,34 @@ namespace Microsoft.AspNet.Mvc.Razor
1111
{
1212
public class MvcCSharpCodeBuilder : CSharpCodeBuilder
1313
{
14+
private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext;
1415
private readonly string _defaultModel;
1516
private readonly string _activateAttribute;
1617

1718
public MvcCSharpCodeBuilder([NotNull] CodeBuilderContext context,
19+
[NotNull] GeneratedTagHelperAttributeContext tagHelperAttributeContext,
1820
[NotNull] string defaultModel,
1921
[NotNull] string activateAttribute)
2022
: base(context)
2123
{
24+
_tagHelperAttributeContext = tagHelperAttributeContext;
2225
_defaultModel = defaultModel;
2326
_activateAttribute = activateAttribute;
2427
}
2528

2629
private string Model { get; set; }
2730

31+
protected override CSharpCodeVisitor CreateCSharpCodeVisitor([NotNull] CSharpCodeWriter writer,
32+
[NotNull] CodeBuilderContext context)
33+
{
34+
var csharpCodeVisitor = base.CreateCSharpCodeVisitor(writer, context);
35+
36+
csharpCodeVisitor.TagHelperRenderer.AttributeValueCodeRenderer =
37+
new MvcTagHelperAttributeValueCodeRenderer(_tagHelperAttributeContext);
38+
39+
return csharpCodeVisitor;
40+
}
41+
2842
protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
2943
{
3044
// Grab the last model chunk so it gets intellisense.

src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,22 @@ public virtual string ActivateAttribute
153153
get { return "Microsoft.AspNet.Mvc.ActivateAttribute"; }
154154
}
155155

156+
/// <summary>
157+
/// Gets the type name used to represent <see cref="ITagHelper"/> model expression properties.
158+
/// </summary>
159+
public virtual string ModelExpressionType
160+
{
161+
get { return "Microsoft.AspNet.Mvc.Rendering.ModelExpression"; }
162+
}
163+
164+
/// <summary>
165+
/// Gets the method name used to create model expressions.
166+
/// </summary>
167+
public virtual string CreateModelExpressionMethod
168+
{
169+
get { return "CreateModelExpression"; }
170+
}
171+
156172
/// <inheritdoc />
157173
public GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream)
158174
{
@@ -173,7 +189,15 @@ public override CodeBuilder DecorateCodeBuilder([NotNull] CodeBuilder incomingBu
173189
[NotNull] CodeBuilderContext context)
174190
{
175191
UpdateCodeBuilder(context);
176-
return new MvcCSharpCodeBuilder(context, DefaultModel, ActivateAttribute);
192+
193+
return new MvcCSharpCodeBuilder(context,
194+
new GeneratedTagHelperAttributeContext
195+
{
196+
ModelExpressionTypeName = ModelExpressionType,
197+
CreateModelExpressionMethodName = CreateModelExpressionMethod
198+
},
199+
DefaultModel,
200+
ActivateAttribute);
177201
}
178202

179203
private void UpdateCodeBuilder(CodeGeneratorContext context)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.AspNet.Razor.Generator;
6+
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
7+
using Microsoft.AspNet.Razor.TagHelpers;
8+
9+
namespace Microsoft.AspNet.Mvc.Razor
10+
{
11+
/// <inheritdoc />
12+
public class MvcTagHelperAttributeValueCodeRenderer : TagHelperAttributeValueCodeRenderer
13+
{
14+
private const string ModelLambdaVariableName = "__model";
15+
16+
private readonly GeneratedTagHelperAttributeContext _context;
17+
18+
/// <summary>
19+
/// Instantiates a new instance of <see cref="MvcTagHelperAttributeValueCodeRenderer"/>.
20+
/// </summary>
21+
/// <param name="context">Contains code generation information for rendering attribute values.</param>
22+
public MvcTagHelperAttributeValueCodeRenderer([NotNull] GeneratedTagHelperAttributeContext context)
23+
{
24+
_context = context;
25+
}
26+
27+
28+
/// <inheritdoc />
29+
/// <remarks>If the attribute being rendered is of the type
30+
/// <see cref="GeneratedTagHelperAttributeContext.ModelExpressionTypeName"/> then a model expression will be
31+
/// created by calling into <see cref="GeneratedTagHelperAttributeContext.CreateModelExpressionMethodName"/>.
32+
/// </remarks>
33+
public override void RenderAttributeValue([NotNull] TagHelperAttributeDescriptor attributeDescriptor,
34+
[NotNull] CSharpCodeWriter writer,
35+
[NotNull] CodeBuilderContext context,
36+
[NotNull] Action<CSharpCodeWriter> renderAttributeValue)
37+
{
38+
var propertyType = attributeDescriptor.PropertyInfo.PropertyType;
39+
40+
if (propertyType.FullName.Equals(_context.ModelExpressionTypeName, StringComparison.Ordinal))
41+
{
42+
writer.WriteStartMethodInvocation(_context.CreateModelExpressionMethodName)
43+
.Write(ModelLambdaVariableName)
44+
.Write(" => ")
45+
.Write(ModelLambdaVariableName)
46+
.Write(".");
47+
48+
// TODO: Enable intellisense for ModelExpressions in https://github.com/aspnet/Mvc/issues/1252.
49+
renderAttributeValue(writer);
50+
51+
writer.WriteEndMethodInvocation(endLine: false);
52+
}
53+
else
54+
{
55+
base.RenderAttributeValue(attributeDescriptor, writer, context, renderAttributeValue);
56+
}
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)