Exemple #1
0
        /// <summary>Initializes a new instance of the <see cref="RazorTemplater" /> class.</summary>
        /// <param name="templateAssemblyPath">The template assembly path. This is the path where the generated templates are stored/cached.
        /// If shadow copy is enabled this path will be ignored and the shadow copy path will be used.</param>
        /// <param name="renderTimeout">The render timeout. This is the time in ms a template is allowed to render itself.</param>
        /// <param name="templateNamespace">The template namespace.</param>
        /// <param name="allowedDirectories">The directories the templates are allowed to read from.</param>
        /// <param name="baseType">Type of the template base class. Defaults to <see cref="TemplateBase" />.</param>
        /// <param name="defaultNamespaces">The default namespaces. Defaults to "System", "System.Collections.Generic", "System.Linq" and "System.Text".</param>
        /// <param name="forbiddenTypes">The forbidden types (FQDN). Defaults to "Task", "Thread", "System.Activator" and "System.Reflection.Assembly".</param>
        /// <param name="language">The language. Defaults to C#.</param>
        /// <param name="sponsor">The sponsor to keep the object alive.</param>
        /// <param name="persistTemplates">If set to <c>true</c> the generated templates are persisted over multiple application runs. Otherwise they are deleted when disposing.</param>
        public RazorTemplater(string templateAssemblyPath, int renderTimeout = 5000, string templateNamespace = "IsolatedRazor.RazorTemplate", List <string> allowedDirectories = null,
                              Type baseType = null, List <string> defaultNamespaces = null, List <string> forbiddenTypes = null, RazorCodeLanguage language = null, ClientSponsor sponsor = null, bool persistTemplates = false)
        {
            RenderTimeout          = renderTimeout;
            this.templateNamespace = templateNamespace;
            this.persistTemplates  = persistTemplates;
            DefaultNamespaces      = defaultNamespaces ?? new List <string>()
            {
                "System", "System.Collections.Generic", "System.Net", "System.Linq", "System.Text", "IsolatedRazor"
            };
            ForbiddenTypes = forbiddenTypes ?? new List <string>()
            {
                "System.Threading.Tasks.Task", "System.Threading.Tasks.Task`1", "System.Threading.Thread", "System.Activator", "System.Reflection.Assembly"
            };
            clientSponsor = sponsor ?? new ClientSponsor(TimeSpan.FromMinutes(1));

            defaultBaseClass = (baseType ?? typeof(TemplateBase)).FullName;
            var host = new RazorEngineHost(language ?? new CSharpRazorCodeLanguage())
            {
                DefaultNamespace = templateNamespace
            };

            DefaultNamespaces.ForEach(n => host.NamespaceImports.Add(n));
            engine   = new RazorTemplateEngine(host);
            provider = host.CodeLanguage.LanguageName == "vb" ? (CodeDomProvider) new VBCodeProvider() : new CSharpCodeProvider();

            adSetup = new AppDomainSetup();
            if (AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles == "true")
            {
                isShadowCopied = true;
                templatePath   = Path.Combine(AppDomain.CurrentDomain.SetupInformation.CachePath, AppDomain.CurrentDomain.SetupInformation.ApplicationName);

                var shadowCopyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                if (shadowCopyDir.Contains("assembly"))
                {
                    shadowCopyDir = shadowCopyDir.Substring(0, shadowCopyDir.LastIndexOf("assembly"));
                }

                var privatePaths = new List <string>();
                foreach (var assemblyLocation in AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic && a.Location.StartsWith(shadowCopyDir)).Select(a => a.Location))
                {
                    privatePaths.Add(Path.GetDirectoryName(assemblyLocation));
                }

                adSetup.ApplicationBase = shadowCopyDir;
                adSetup.PrivateBinPath  = String.Join(";", privatePaths);
            }
            else
            {
                isShadowCopied          = false;
                templatePath            = templateAssemblyPath;
                adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
                adSetup.PrivateBinPath  = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
            }

            var resolver = new DefaultAssemblyResolver();

            resolver.AddSearchDirectory(Path.GetDirectoryName(adSetup.ApplicationBase));
            readerParameters = new ReaderParameters()
            {
                AssemblyResolver = resolver
            };

            if (templateCache == null)
            {
                var path = Path.Combine(templatePath, TEMPLATE_CACHE_FILE);
                if (persistTemplates && File.Exists(path))
                {
                    using (var filestream = File.Open(path, FileMode.Open))
                    {
                        var formatter = new BinaryFormatter();
                        templateCache = (TemplateCache)formatter.Deserialize(filestream);
                    }
                }
                else
                {
                    templateCache = new TemplateCache();
                }
            }

            Directory.CreateDirectory(templatePath);

            permissionSet = new PermissionSet(PermissionState.None);
            permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));                              // run the code
            permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.RemotingConfiguration));                  // remoting lifetime (sponsor)
            permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, templatePath));                       // read templates
            permissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));             // support dynamic

            if (allowedDirectories != null)
            {
                allowedDirectories.ForEach(dir => permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, dir)));
            }

            RecycleAppDomain();
        }
Exemple #2
0
        /// <summary>Compiles the specified templates and stores it in the cache with the given group name.</summary>
        /// <param name="groupName">The group name.</param>
        /// <param name="templates">The template group.</param>
        /// <param name="timestamp">The time-stamp the template (NOT the assembly) was created.</param>
        /// <param name="baseTypeName">Type of the template base class as its FQDN. Defaults to the default base class.</param>
        /// <param name="additionalNamespaces">The additional namespaces.</param>
        /// <param name="generatedCodePath">If not NULL the generated code will be saved to this path.</param>
        /// <returns>The path to the generated assembly.</returns>
        /// <exception cref="System.ObjectDisposedException">RazorTemplater already disposed.</exception>
        /// <exception cref="CompilerException">The supplied template is not valid.</exception>
        public Task <string> CompileAsync(string groupName, Dictionary <string, string> templates, DateTime timestamp, string baseTypeName = null,
                                          List <string> additionalNamespaces = null, string generatedCodePath = null)
        {
            if (appDomain == null)
            {
                throw new ObjectDisposedException("RazorTemplater");
            }

            var cachedTemplate = templateCache.Get(groupName, templates, timestamp);

            if (!String.IsNullOrWhiteSpace(cachedTemplate))
            {
                return(Task.FromResult(cachedTemplate));
            }

            return(Task.Run(() =>
            {
                engine.Host.DefaultBaseClass = baseTypeName ?? defaultBaseClass;
                if (additionalNamespaces != null)
                {
                    additionalNamespaces.ForEach(n => engine.Host.NamespaceImports.Add(n));
                }

                var razorTemplates = new List <GeneratorResults>();
                foreach (var template in templates)
                {
                    engine.Host.DefaultClassName = ClassName(groupName + "_" + template.Key);

                    var razorTemplate = engine.GenerateCode(new StringReader(template.Value));
                    razorTemplates.Add(razorTemplate);

                    if (!String.IsNullOrWhiteSpace(generatedCodePath))
                    {
                        SaveGeneratedCode(razorTemplate, generatedCodePath + String.Format(".{0}.cs", engine.Host.DefaultClassName));
                    }
                    else if (isShadowCopied)
                    {
                        SaveGeneratedCode(razorTemplate, Path.Combine(templatePath, engine.Host.DefaultClassName + ".cs"));
                    }
                }

                var outputName = groupName;
                foreach (char c in System.IO.Path.GetInvalidFileNameChars())
                {
                    outputName = outputName.Replace(c, '_');
                }

                var compilerParameters = new CompilerParameters()
                {
                    GenerateExecutable = false,
                    IncludeDebugInformation = false,
                    OutputAssembly = Path.Combine(templatePath, outputName + "." + DateTime.Now.ToString("yyyyMMddHHmmss") + ".dll"),                           // date-time to avoid accessing locked files
                    CompilerOptions = "/target:library /optimize /define:RAZORTEMPLATE"
                };

                var assemblies = AppDomain.CurrentDomain.GetAssemblies()
                                 .Where(a => !a.IsDynamic && File.Exists(a.Location))
                                 .GroupBy(a => a.GetName().Name).Select(g => g.First(y => y.GetName().Version == g.Max(x => x.GetName().Version)))        // group assemblies on FullName to avoid loading duplicate assemblies
                                 .Select(a => a.Location);
                compilerParameters.ReferencedAssemblies.AddRange(assemblies.ToArray());

                var compiledAssembly = provider.CompileAssemblyFromDom(compilerParameters, razorTemplates.Select(t => t.GeneratedCode).ToArray());
                templater.RemoveFromAssemblyCache(compiledAssembly.PathToAssembly);

                if (additionalNamespaces != null)
                {
                    engine.Host.NamespaceImports.Clear();
                    DefaultNamespaces.ForEach(n => engine.Host.NamespaceImports.Add(n));
                }

                if (compiledAssembly.Errors.Count > 0)
                {
                    var message = String.Empty;
                    foreach (var error in compiledAssembly.Errors)
                    {
                        if (error is CompilerError)
                        {
                            var compilerError = error as CompilerError;
                            message += compilerError.ErrorText + Environment.NewLine;
                        }
                        else
                        {
                            message += error.ToString() + Environment.NewLine;
                        }
                    }

                    if (File.Exists(compiledAssembly.PathToAssembly))
                    {
                        File.Delete(compiledAssembly.PathToAssembly);
                    }
                    throw new CompilerException(message, compiledAssembly.Errors);
                }

                ValidateAssembly(compiledAssembly);

                var assemblyPath = compiledAssembly.PathToAssembly;
                templateCache.Set(groupName, assemblyPath, templates, timestamp);

                return assemblyPath;
            }));
        }