/src/RazorEngine/Compilation/CompilerServiceBase.cs
C# | 217 lines | 137 code | 35 blank | 45 comment | 22 complexity | 6b457b5ef2ae15bd54eee6659dd094bd MD5 | raw file
Possible License(s): BSD-3-Clause
- using System.Web.Mvc.Razor;
- using System.Web.Razor.Parser.SyntaxTree;
- using RazorEngine.Compilation.CSharp;
-
- namespace RazorEngine.Compilation
- {
- using System;
- using System.CodeDom;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using System.Web.Razor;
- using System.Web.Razor.Generator;
- using System.Web.Razor.Parser;
-
- using Templating;
-
- /// <summary>
- /// Provides a base implementation of a compiler service.
- /// </summary>
- public abstract class CompilerServiceBase : ICompilerService
- {
- #region Constructor
- /// <summary>
- /// Initialises a new instance of <see cref="CompilerServiceBase"/>
- /// </summary>
- /// <param name="codeLanguage">The code language.</param>
- /// <param name="markupParser">The markup parser.</param>
- protected CompilerServiceBase(RazorCodeLanguage codeLanguage, MarkupParser markupParser)
- {
- if (codeLanguage == null)
- throw new ArgumentNullException("codeLanguage");
-
- CodeLanguage = codeLanguage;
- MarkupParser = markupParser ?? new HtmlMarkupParser();
- }
- #endregion
-
- #region Properties
- /// <summary>
- /// Gets the code language.
- /// </summary>
- public RazorCodeLanguage CodeLanguage { get; private set; }
-
- /// <summary>
- /// Gets the markup parser.
- /// </summary>
- public MarkupParser MarkupParser { get; private set; }
- #endregion
-
- #region Methods
- /// <summary>
- /// Builds a type name for the specified template type and model type.
- /// </summary>
- /// <param name="templateType">The template type.</param>
- /// <param name="modelType">The model type.</param>
- /// <returns>The string type name (including namespace).</returns>
- public virtual string BuildTypeName(Type templateType, Type modelType)
- {
- if (templateType == null)
- throw new ArgumentNullException("templateType");
-
- if (!templateType.IsGenericTypeDefinition && !templateType.IsGenericType)
- return templateType.FullName;
-
- if (modelType == null)
- throw new ArgumentException("The template type is a generic defintion, and no model type has been supplied.");
-
- bool @dynamic = CompilerServices.IsDynamicType(modelType);
- Type genericType = templateType.MakeGenericType(modelType);
-
- return BuildTypeNameInternal(genericType, @dynamic);
- }
-
- /// <summary>
- /// Builds a type name for the specified generic type.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="isDynamic">Is the model type dynamic?</param>
- /// <returns>The string typename (including namespace and generic type parameters).</returns>
- public abstract string BuildTypeNameInternal(Type type, bool isDynamic);
-
- /// <summary>
- /// Compiles the type defined in the specified type context.
- /// </summary>
- /// <param name="context">The type context which defines the type to compile.</param>
- /// <returns>The compiled type.</returns>
- public abstract Type CompileType(TypeContext context);
-
- /// <summary>
- /// Generates any required contructors for the specified type.
- /// </summary>
- /// <param name="constructors">The set of constructors.</param>
- /// <param name="codeType">The code type declaration.</param>
- private static void GenerateConstructors(IEnumerable<ConstructorInfo> constructors, CodeTypeDeclaration codeType)
- {
- if (constructors == null || !constructors.Any())
- return;
-
- var existingConstructors = codeType.Members.OfType<CodeConstructor>().ToArray();
- foreach (var existingConstructor in existingConstructors)
- codeType.Members.Remove(existingConstructor);
-
- foreach (var constructor in constructors)
- {
- var ctor = new CodeConstructor();
- ctor.Attributes = MemberAttributes.Public;
-
- foreach (var param in constructor.GetParameters())
- {
- ctor.Parameters.Add(new CodeParameterDeclarationExpression(param.ParameterType, param.Name));
- ctor.BaseConstructorArgs.Add(new CodeSnippetExpression(param.Name));
- }
-
- codeType.Members.Add(ctor);
- }
- }
-
- /// <summary>
- /// Gets the code compile unit used to compile a type.
- /// </summary>
- /// <param name="className">The class name.</param>
- /// <param name="template">The template to compile.</param>
- /// <param name="namespaceImports">The set of namespace imports.</param>
- /// <param name="templateType">The template type.</param>
- /// <param name="modelType">The model type.</param>
- /// <returns>A <see cref="CodeCompileUnit"/> used to compile a type.</returns>
- public CodeCompileUnit GetCodeCompileUnit(string className, string template, ISet<string> namespaceImports, Type templateType, Type modelType)
- {
- if (string.IsNullOrEmpty(className))
- throw new ArgumentException("Class name is required.");
-
- if (string.IsNullOrEmpty(template))
- throw new ArgumentException("Template is required.");
-
- templateType = templateType
- ?? ((modelType == null)
- ? typeof(TemplateBase)
- : typeof(TemplateBase<>));
-
- var host = new MvcWebPageRazorHost(CodeLanguage, () => MarkupParser)
- {
- DefaultBaseClass = BuildTypeName(templateType, modelType),
- DefaultClassName = className,
- DefaultNamespace = "CompiledRazorTemplates.Dynamic",
- GeneratedClassContext = new GeneratedClassContext("Execute", "Write", "WriteLiteral",
- "WriteTo", "WriteLiteralTo",
- "RazorEngine.Templating.TemplateWriter",
- "WriteSection")
- };
-
- host.NamespaceImports.Add("ServiceStack.Markdown.Html");
-
- var templateNamespaces = templateType.GetCustomAttributes(typeof (RequireNamespacesAttribute), true)
- .Cast<RequireNamespacesAttribute>()
- .SelectMany(att => att.Namespaces);
-
- foreach (string ns in templateNamespaces)
- namespaceImports.Add(ns);
-
- foreach (string @namespace in namespaceImports)
- host.NamespaceImports.Add(@namespace);
-
- var engine = new RazorTemplateEngine(host);
- GeneratorResults result;
- using (var reader = new StringReader(template))
- {
- result = engine.GenerateCode(reader);
- }
-
- var type = result.GeneratedCode.Namespaces[0].Types[0];
- if (modelType != null)
- {
- if (CompilerServices.IsAnonymousType(modelType))
- {
- type.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(HasDynamicModelAttribute))));
- }
- }
-
- GenerateConstructors(CompilerServices.GetConstructors(templateType), type);
-
- var statement = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Clear");
- foreach (CodeTypeMember member in type.Members)
- {
- if (member.Name.Equals("Execute"))
- {
- ((CodeMemberMethod)member).Statements.Insert(0, new CodeExpressionStatement(statement));
- break;
- }
- }
-
- return result.GeneratedCode;
- }
- #endregion
-
- public IEnumerable<T> AllNodesOfType<T>(Block block)
- {
- if (block is T)
- yield return (T)(object)block;
-
- foreach (var syntaxTreeNode in block.Children)
- {
- if (syntaxTreeNode is T)
- yield return (T)(object)syntaxTreeNode;
-
- var childBlock = syntaxTreeNode as Block;
- if (childBlock == null) continue;
-
- foreach (var variable in AllNodesOfType<T>(childBlock))
- {
- yield return variable;
- }
- }
- }
- }
- }