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
This commit is contained in:
NTaylorMullen 2014-10-07 20:50:20 -07:00
Родитель ad76a3c8fb
Коммит 2005c3cd85
5 изменённых файлов: 121 добавлений и 3 удалений

Просмотреть файл

@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <summary>
/// Describes an <see cref="System.Linq.Expressions.Expression"/> passed to a tag helper.
/// </summary>
public class ModelExpression
public sealed class ModelExpression
{
/// <summary>
/// Initializes a new instance of the <see cref="ModelExpression"/> class.

Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// Contains information for the <see cref="ITagHelper"/> attribute code generation process.
/// </summary>
public class GeneratedTagHelperAttributeContext
{
/// <summary>
/// Name of the model expression type.
/// </summary>
public string ModelExpressionTypeName { get; set; }
/// <summary>
/// Name the method to create <c>ModelExpression</c>s.
/// </summary>
public string CreateModelExpressionMethodName { get; set; }
}
}

Просмотреть файл

@ -11,20 +11,34 @@ namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcCSharpCodeBuilder : CSharpCodeBuilder
{
private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext;
private readonly string _defaultModel;
private readonly string _activateAttribute;
public MvcCSharpCodeBuilder([NotNull] CodeBuilderContext context,
[NotNull] string defaultModel,
[NotNull] string activateAttribute)
[NotNull] string activateAttribute,
[NotNull] GeneratedTagHelperAttributeContext tagHelperAttributeContext)
: base(context)
{
_tagHelperAttributeContext = tagHelperAttributeContext;
_defaultModel = defaultModel;
_activateAttribute = activateAttribute;
}
private string Model { get; set; }
protected override CSharpCodeVisitor CreateCSharpCodeVisitor([NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext context)
{
var csharpCodeVisitor = base.CreateCSharpCodeVisitor(writer, context);
csharpCodeVisitor.TagHelperRenderer.AttributeValueCodeRenderer =
new MvcTagHelperAttributeValueCodeRenderer(_tagHelperAttributeContext);
return csharpCodeVisitor;
}
protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
{
// Grab the last model chunk so it gets intellisense.

Просмотреть файл

@ -153,6 +153,22 @@ namespace Microsoft.AspNet.Mvc.Razor
get { return "Microsoft.AspNet.Mvc.ActivateAttribute"; }
}
/// <summary>
/// Gets the type name used to represent <see cref="ITagHelper"/> model expression properties.
/// </summary>
public virtual string ModelExpressionType
{
get { return "Microsoft.AspNet.Mvc.Rendering.ModelExpression"; }
}
/// <summary>
/// Gets the method name used to create model expressions.
/// </summary>
public virtual string CreateModelExpressionMethod
{
get { return "CreateModelExpression"; }
}
/// <inheritdoc />
public GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream)
{
@ -173,7 +189,15 @@ namespace Microsoft.AspNet.Mvc.Razor
[NotNull] CodeBuilderContext context)
{
UpdateCodeBuilder(context);
return new MvcCSharpCodeBuilder(context, DefaultModel, ActivateAttribute);
return new MvcCSharpCodeBuilder(context,
DefaultModel,
ActivateAttribute,
new GeneratedTagHelperAttributeContext
{
ModelExpressionTypeName = ModelExpressionType,
CreateModelExpressionMethodName = CreateModelExpressionMethod
});
}
private void UpdateCodeBuilder(CodeGeneratorContext context)

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor
{
/// <inheritdoc />
public class MvcTagHelperAttributeValueCodeRenderer : TagHelperAttributeValueCodeRenderer
{
private const string ModelLambdaVariableName = "__model";
private readonly GeneratedTagHelperAttributeContext _context;
/// <summary>
/// Instantiates a new instance of <see cref="MvcTagHelperAttributeValueCodeRenderer"/>.
/// </summary>
/// <param name="context">Contains code generation information for rendering attribute values.</param>
public MvcTagHelperAttributeValueCodeRenderer([NotNull] GeneratedTagHelperAttributeContext context)
{
_context = context;
}
/// <inheritdoc />
/// <remarks>If the attribute being rendered is of the type
/// <see cref="GeneratedTagHelperAttributeContext.ModelExpressionTypeName"/> then a model expression will be
/// created by calling into <see cref="GeneratedTagHelperAttributeContext.CreateModelExpressionMethodName"/>.
/// </remarks>
public override void RenderAttributeValue([NotNull] TagHelperAttributeDescriptor attributeDescriptor,
[NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext codeBuilderContext,
[NotNull] Action<CSharpCodeWriter> renderAttributeValue)
{
var propertyType = attributeDescriptor.PropertyInfo.PropertyType;
if (propertyType.FullName.Equals(_context.ModelExpressionTypeName, StringComparison.Ordinal))
{
writer.WriteStartMethodInvocation(_context.CreateModelExpressionMethodName)
.Write(ModelLambdaVariableName)
.Write(" => ")
.Write(ModelLambdaVariableName)
.Write(".");
renderAttributeValue(writer);
writer.WriteEndMethodInvocation(endLine: false);
}
else
{
base.RenderAttributeValue(attributeDescriptor, writer, codeBuilderContext, renderAttributeValue);
}
}
}
}