diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/Microsoft.AspNet.Mvc.Razor.Host.kproj b/src/Microsoft.AspNet.Mvc.Razor.Host/Microsoft.AspNet.Mvc.Razor.Host.kproj index 577f5a3481..227e4f8f8a 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/Microsoft.AspNet.Mvc.Razor.Host.kproj +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/Microsoft.AspNet.Mvc.Razor.Host.kproj @@ -25,6 +25,10 @@ + + + + diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/ModelChunk.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/ModelChunk.cs new file mode 100644 index 0000000000..0b034fd66a --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/ModelChunk.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNet.Razor.Generator.Compiler; + +namespace Microsoft.AspNet.Mvc.Razor +{ + public class ModelChunk : Chunk + { + /// + /// Represents the chunk for an @model statement. + /// + /// The base type of the view. + /// The type of the view's Model. + public ModelChunk(string baseType, string modelType) + { + BaseType = baseType; + ModelType = modelType; + } + + public string BaseType { get; private set; } + public string ModelType { get; private set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/ModelChunkVisitor.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/ModelChunkVisitor.cs new file mode 100644 index 0000000000..8c38523769 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/ModelChunkVisitor.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; + +namespace Microsoft.AspNet.Mvc.Razor +{ + public class ModelChunkVisitor : MvcCSharpCodeVisitor + { + public ModelChunkVisitor([NotNull] CSharpCodeWriter writer, + [NotNull] CodeGeneratorContext context) + : base(writer, context) + { } + + protected override void Visit(ModelChunk chunk) + { + var csharpVisitor = new CSharpCodeVisitor(Writer, Context); + + Writer.Write(chunk.BaseType).Write("<"); + csharpVisitor.CreateExpressionCodeMapping(chunk.ModelType, chunk); + Writer.Write(">"); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/ModelCodeGenerator.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/ModelCodeGenerator.cs new file mode 100644 index 0000000000..632678dcba --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/ModelCodeGenerator.cs @@ -0,0 +1,41 @@ +using System; +using Microsoft.AspNet.Mvc.Razor; +using Microsoft.AspNet.Razor.Parser.SyntaxTree; + +namespace Microsoft.AspNet.Razor.Generator +{ + public class ModelCodeGenerator : SpanCodeGenerator + { + public ModelCodeGenerator(string baseType, string modelType) + { + BaseType = baseType; + ModelType = modelType; + } + + public string BaseType { get; private set; } + public string ModelType { get; private set; } + + public override void GenerateCode(Span target, CodeGeneratorContext context) + { + var modelChunk = new ModelChunk(BaseType, ModelType); + context.CodeTreeBuilder.AddChunk(modelChunk, target, topLevel: true); + } + + public override string ToString() + { + return "Full Model Type: " + BaseType + "<" + ModelType + ">"; + } + + public override bool Equals(object obj) + { + var other = obj as ModelCodeGenerator; + return other != null && + string.Equals(ModelType, other.ModelType, StringComparison.Ordinal); + } + + public override int GetHashCode() + { + return ModelType.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs new file mode 100644 index 0000000000..887466eed5 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler; +using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; + +namespace Microsoft.AspNet.Mvc.Razor +{ + public abstract class MvcCSharpChunkVisitor : CodeVisitor + { + public MvcCSharpChunkVisitor([NotNull] CSharpCodeWriter writer, + [NotNull] CodeGeneratorContext context) + : base(writer, context) + { } + + public override void Accept(Chunk chunk) + { + if (chunk is InjectChunk) + { + Visit((InjectChunk)chunk); + } + else if (chunk is ModelChunk) + { + Visit((ModelChunk)chunk); + } + else + { + base.Accept(chunk); + } + } + + protected abstract void Visit(InjectChunk chunk); + protected abstract void Visit(ModelChunk chunk); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeBuilder.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeBuilder.cs index a3a9ac5c63..c7a510feda 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeBuilder.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeBuilder.cs @@ -2,8 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler; using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; namespace Microsoft.AspNet.Mvc.Razor @@ -15,6 +17,29 @@ namespace Microsoft.AspNet.Mvc.Razor { } + protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer) + { + var chunks = Context.CodeTreeBuilder.CodeTree.Chunks; + + // If there were any model chunks then we need to modify the class declaration signature. + if (chunks.OfType().Any()) + { + writer.Write(string.Format(CultureInfo.CurrentCulture, "public class {0} : ", Context.ClassName)); + + var modelVisitor = new ModelChunkVisitor(writer, Context); + // This generates the base class signature + modelVisitor.Accept(chunks); + + writer.WriteLine(); + + return new CSharpCodeWritingScope(writer); + } + else + { + return base.BuildClassDeclaration(writer); + } + } + protected override void BuildConstructor([NotNull] CSharpCodeWriter writer) { writer.WriteLineHiddenDirective(); diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeVistor.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeVistor.cs index 89a843d307..334873d574 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeVistor.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcCSharpCodeVistor.cs @@ -2,31 +2,22 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Razor.Generator; -using Microsoft.AspNet.Razor.Generator.Compiler; using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; namespace Microsoft.AspNet.Mvc.Razor { - public abstract class MvcCSharpCodeVisitor : CodeVisitor + public abstract class MvcCSharpCodeVisitor : MvcCSharpChunkVisitor { - public MvcCSharpCodeVisitor([NotNull] CSharpCodeWriter writer, + public MvcCSharpCodeVisitor([NotNull] CSharpCodeWriter writer, [NotNull] CodeGeneratorContext context) : base(writer, context) + { } + + protected override void Visit(InjectChunk chunk) { } - - public override void Accept(Chunk chunk) + protected override void Visit(ModelChunk chunk) { - if (chunk is InjectChunk) - { - Visit((InjectChunk)chunk); - } - else - { - base.Accept(chunk); - } } - - protected abstract void Visit(InjectChunk chunk); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs index 6b19279dac..6601e4920c 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs @@ -1,7 +1,6 @@ // 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.Globalization; using Microsoft.AspNet.Mvc.Razor.Host; using Microsoft.AspNet.Razor.Generator; using Microsoft.AspNet.Razor.Parser; @@ -13,7 +12,6 @@ namespace Microsoft.AspNet.Mvc.Razor { public class MvcRazorCodeParser : CSharpCodeParser { - private const string GenericTypeFormat = "{0}<{1}>"; private const string ModelKeyword = "model"; private const string InjectKeyword = "inject"; private readonly string _baseType; @@ -138,12 +136,7 @@ namespace Microsoft.AspNet.Mvc.Razor private SpanCodeGenerator CreateModelCodeGenerator(string model) { - // In the event we have an empty model, the name we generate does not matter since it's a parser error. - // We'll use the non-generic version of the base type. - var baseType = string.IsNullOrEmpty(model) ? - _baseType : - string.Format(CultureInfo.InvariantCulture, GenericTypeFormat, _baseType, model); - return new SetBaseTypeCodeGenerator(baseType); + return new ModelCodeGenerator(_baseType, model); } } }