Beispiel #1
0
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            var dynamicObject = Model as RazorDynamicObject;

            if (dynamicObject != null)
            {
                return(dynamicObject.TryGetMember(binder, out result));
            }

            Type modelType = Model.GetType();
            var  prop      = modelType.GetProperty(binder.Name);

            if (prop == null)
            {
                result = null;
                return(false);
            }

            object value = prop.GetValue(Model, null);

            if (value == null)
            {
                result = value;
                return(true);
            }

            Type valueType = value.GetType();

            result = (CompilerServices.IsAnonymousType(valueType))
                         ? new RazorDynamicObject {
                Model = value
            }
                         : value;
            return(true);
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        /// <summary>
        /// Creates the compile results for the specified <see cref="TypeContext"/>.
        /// </summary>
        /// <param name="context">The type context.</param>
        /// <returns>The compiler results.</returns>
        private CompilerResults Compile(TypeContext context)
        {
            var compileUnit = GetCodeCompileUnit(
                context.ClassName,
                context.TemplateContent,
                context.Namespaces,
                context.TemplateType,
                context.ModelType);

            var @params = new CompilerParameters {
                GenerateInMemory        = true,
                GenerateExecutable      = false,
                IncludeDebugInformation = false,
                CompilerOptions         = "/target:library /optimize",
                TempFiles = { KeepFiles = true }
            };

            var assemblies = CompilerServices
                             .GetLoadedAssemblies()
                             .Where(a => !a.IsDynamic)
                             .Select(a => a.Location)
                             .ToArray();

            @params.ReferencedAssemblies.AddRange(assemblies);

            if (Env.IsMono)
            {
                for (var i = @params.ReferencedAssemblies.Count - 1; i >= 0; i--)
                {
                    var assembly = @params.ReferencedAssemblies[i];
                    foreach (var filterAssembly in DuplicatedAssmebliesInMono)
                    {
                        if (assembly.Contains(filterAssembly))
                        {
                            @params.ReferencedAssemblies.RemoveAt(i);
                        }
                    }
                }
            }

            var results = CodeDomProvider.CompileAssemblyFromDom(@params, compileUnit);

            //Tricky: Don't forget to cleanup.
            // Simply setting KeepFiles = false and then calling
            // dispose on the parent TempFilesCollection won't
            // clean up. So, create a new collection and
            // explicitly mark the files for deletion.
            var tempFilesMarkedForDeletion = new TempFileCollection(null);

            @params.TempFiles
            .OfType <string>()
            .ForEach(file => tempFilesMarkedForDeletion.AddFile(file, false));

            using ( tempFilesMarkedForDeletion )
            {
                if (results.Errors != null && results.Errors.HasErrors)
                {
                    throw new TemplateCompilationException(results);
                }

                return(results);
            }
        }
Beispiel #4
0
        /// <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 RazorEngineHost(CodeLanguage)
            {
                DefaultBaseClass      = BuildTypeName(templateType, modelType),
                DefaultClassName      = className,
                DefaultNamespace      = "CompiledRazorTemplates.Dynamic",
                GeneratedClassContext = new GeneratedClassContext(
                    "Execute", "Write", "WriteLiteral",
                    "WriteTo", "WriteLiteralTo",
                    "ServiceStack.Razor2.Templating.TemplateWriter",
                    "WriteSection")
                {
                    ResolveUrlMethodName = "Href"
                }
            };

            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);
        }
Beispiel #5
0
 /// <summary>
 /// Initializes a new instance of <see cref="TypeContext"/>.
 /// </summary>
 public TypeContext()
 {
     ClassName  = CompilerServices.GenerateClassName();
     Namespaces = new HashSet <string>();
 }