diff --git a/src/source/RazorEngine.Core/Compilation/CSharp/CSharpDirectCompilerService.cs b/src/source/RazorEngine.Core/Compilation/CSharp/CSharpDirectCompilerService.cs index a53fcb41..e51c7a79 100644 --- a/src/source/RazorEngine.Core/Compilation/CSharp/CSharpDirectCompilerService.cs +++ b/src/source/RazorEngine.Core/Compilation/CSharp/CSharpDirectCompilerService.cs @@ -1,4 +1,6 @@ -namespace RazorEngine.Compilation.CSharp +using RazorEngine.Configuration; + +namespace RazorEngine.Compilation.CSharp { using System; using System.Collections.Generic; @@ -29,11 +31,11 @@ public class CSharpDirectCompilerService : DirectCompilerServiceBase /// The markup parser factory to use. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed"), SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed in base class: DirectCompilerServiceBase")] [SecurityCritical] - public CSharpDirectCompilerService(bool strictMode = true, Func markupParserFactory = null) + public CSharpDirectCompilerService(bool strictMode = true, Func markupParserFactory = null, ITemplateServiceConfiguration config = null) : base( new CSharpRazorCodeLanguage(strictMode), new CSharpCodeProvider(), - markupParserFactory) { } + markupParserFactory, config) { } #endregion /// diff --git a/src/source/RazorEngine.Core/Compilation/CSharp/CSharpRoslynCompilerService.cs b/src/source/RazorEngine.Core/Compilation/CSharp/CSharpRoslynCompilerService.cs index 69b80ce1..0281961f 100644 --- a/src/source/RazorEngine.Core/Compilation/CSharp/CSharpRoslynCompilerService.cs +++ b/src/source/RazorEngine.Core/Compilation/CSharp/CSharpRoslynCompilerService.cs @@ -17,6 +17,7 @@ using System.Globalization; #endif using RazorEngine.Compilation.ReferenceResolver; +using RazorEngine.Configuration; namespace RazorEngine.Roslyn.CSharp { @@ -31,7 +32,7 @@ public class CSharpRoslynCompilerService : RoslynCompilerServiceBase /// We need a CodeDom instance as pre Razor4 uses CodeDom /// internally and we need to generate the source code file... /// - private Microsoft.CSharp.CSharpCodeProvider _codeDomProvider; + private Microsoft.CSharp.CSharpCodeProvider _codeDomProvider; #endif /// /// Creates a new CSharpRoslynCompilerService instance. @@ -39,10 +40,16 @@ public class CSharpRoslynCompilerService : RoslynCompilerServiceBase /// /// [SecurityCritical] - public CSharpRoslynCompilerService(bool strictMode = true, Func markupParserFactory = null) - : base( - new RazorEngine.Compilation.CSharp.CSharpRazorCodeLanguage(strictMode), - markupParserFactory) { + public CSharpRoslynCompilerService(bool strictMode = true, Func markupParserFactory = null) : this(null, strictMode, markupParserFactory) { } + + /// + /// Creates a new CSharpRoslynCompilerService instance. + /// + /// + /// + public CSharpRoslynCompilerService(ITemplateServiceConfiguration config, bool strictMode = true, Func markupParserFactory = null) + : base(new RazorEngine.Compilation.CSharp.CSharpRazorCodeLanguage(strictMode), markupParserFactory, config) + { #if !RAZOR4 _codeDomProvider = new Microsoft.CSharp.CSharpCodeProvider(); #endif diff --git a/src/source/RazorEngine.Core/Compilation/CompilerServiceBase.cs b/src/source/RazorEngine.Core/Compilation/CompilerServiceBase.cs index 63041358..89f6b006 100644 --- a/src/source/RazorEngine.Core/Compilation/CompilerServiceBase.cs +++ b/src/source/RazorEngine.Core/Compilation/CompilerServiceBase.cs @@ -1,4 +1,6 @@ -namespace RazorEngine.Compilation +using RazorEngine.Configuration; + +namespace RazorEngine.Compilation { using System; using System.CodeDom; @@ -37,6 +39,8 @@ public abstract class CompilerServiceBase : ICompilerService /// protected internal const string ClassNamePrefix = "RazorEngine_"; + protected internal ITemplateServiceConfiguration _config; + /// /// This class only exists because we cannot use Func<ParserBase> in non security-critical class. /// @@ -75,11 +79,22 @@ public ParserBase Create() protected CompilerServiceBase(RazorCodeLanguage codeLanguage, ParserBaseCreator markupParserFactory) { Contract.Requires(codeLanguage != null); - CodeLanguage = codeLanguage; MarkupParserFactory = markupParserFactory ?? new ParserBaseCreator(null); ReferenceResolver = new UseCurrentAssembliesReferenceResolver(); } + + /// + /// Initialises a new instance of + /// + /// The code language. + /// The markup parser factory. + [SecurityCritical] + protected CompilerServiceBase(RazorCodeLanguage codeLanguage, ParserBaseCreator markupParserFactory, ITemplateServiceConfiguration config) : this(codeLanguage, markupParserFactory) + { + Contract.Requires(codeLanguage != null); + _config = config; + } #endregion #region Properties @@ -132,7 +147,14 @@ protected CompilerServiceBase(RazorCodeLanguage codeLanguage, ParserBaseCreator /// Tries to create and return a unique temporary directory. /// /// the (already created) temporary directory - protected static string GetDefaultTemporaryDirectory() + ///protected static string GetDefaultTemporaryDirectory() => GetDefaultTemporaryDirectory(null); + protected static string GetDefaultTemporaryDirectory() => GetDefaultTemporaryDirectory(null); + + /// + /// Tries to create and return a unique temporary directory. + /// + /// the (already created) temporary directory + protected static string GetDefaultTemporaryDirectory(ITemplateServiceConfiguration config) { var created = false; var tried = 0; @@ -142,7 +164,14 @@ protected static string GetDefaultTemporaryDirectory() tried++; try { - tempDirectory = Path.Combine(Path.GetTempPath(), "RazorEngine_" + Path.GetRandomFileName()); + string tempDirectoryPath = Path.GetTempPath(); + + if (!string.IsNullOrEmpty(config?.TemporaryDirectory)) + { + tempDirectoryPath = config.TemporaryDirectory; + } + + tempDirectory = Path.Combine(tempDirectoryPath, "RazorEngine_" + Path.GetRandomFileName()); if (!Directory.Exists(tempDirectory)) { Directory.CreateDirectory(tempDirectory); @@ -174,6 +203,16 @@ protected virtual string GetTemporaryDirectory() return GetDefaultTemporaryDirectory(); } + /// + /// Returns a new temporary directory ready to be used. + /// This can be overwritten in subclases to change the created directories. + /// + /// + protected virtual string GetTemporaryDirectory(ITemplateServiceConfiguration config) + { + return GetDefaultTemporaryDirectory(config); + } + /// /// Builds a type name for the specified template type. /// diff --git a/src/source/RazorEngine.Core/Compilation/CompilerServiceBuilder.cs b/src/source/RazorEngine.Core/Compilation/CompilerServiceBuilder.cs index 23508dfb..3138c151 100644 --- a/src/source/RazorEngine.Core/Compilation/CompilerServiceBuilder.cs +++ b/src/source/RazorEngine.Core/Compilation/CompilerServiceBuilder.cs @@ -40,10 +40,20 @@ public static void SetCompilerServiceFactory(ICompilerServiceFactory factory) /// The code language. /// The compiler service instance. public static ICompilerService GetCompilerService(Language language) + { + return GetCompilerService(language, null); + } + + /// + /// Gets the for the specfied language. + /// + /// The code language. + /// The compiler service instance. + public static ICompilerService GetCompilerService(Language language, ITemplateServiceConfiguration config) { lock (sync) { - return _factory.CreateCompilerService(language); + return _factory.CreateCompilerService(language, config); } } @@ -56,9 +66,9 @@ public static ICompilerService GetDefaultCompilerService() { var config = RazorEngineConfigurationSection.GetConfiguration(); if (config == null) - return GetCompilerService(Language.CSharp); + return GetCompilerService(Language.CSharp, null); - return GetCompilerService(config.DefaultLanguage); + return GetCompilerService(config.DefaultLanguage, null); } #endregion } diff --git a/src/source/RazorEngine.Core/Compilation/DefaultCompilerServiceFactory.cs b/src/source/RazorEngine.Core/Compilation/DefaultCompilerServiceFactory.cs index 33b44b51..97f29c6d 100644 --- a/src/source/RazorEngine.Core/Compilation/DefaultCompilerServiceFactory.cs +++ b/src/source/RazorEngine.Core/Compilation/DefaultCompilerServiceFactory.cs @@ -1,4 +1,6 @@ -namespace RazorEngine.Compilation +using RazorEngine.Configuration; + +namespace RazorEngine.Compilation { using System; using System.Diagnostics.CodeAnalysis; @@ -22,17 +24,29 @@ public class DefaultCompilerServiceFactory : ICompilerServiceFactory [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] [SecuritySafeCritical] public ICompilerService CreateCompilerService(Language language) + { + return CreateCompilerService(language, null); + } + + /// + /// Creates a that supports the specified language. + /// + /// The . + /// An instance of . + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SecuritySafeCritical] + public ICompilerService CreateCompilerService(Language language, ITemplateServiceConfiguration config) { switch (language) { case Language.CSharp: - return new CSharpDirectCompilerService(); + return new CSharpDirectCompilerService(config: config); case Language.VisualBasic: #if RAZOR4 throw new NotSupportedException("Razor4 doesn't support VB.net apparently."); #else - return new VBDirectCompilerService(); + return new VBDirectCompilerService(config: config); #endif default: diff --git a/src/source/RazorEngine.Core/Compilation/DirectCompilerServiceBase.cs b/src/source/RazorEngine.Core/Compilation/DirectCompilerServiceBase.cs index 98444356..d6101ee6 100644 --- a/src/source/RazorEngine.Core/Compilation/DirectCompilerServiceBase.cs +++ b/src/source/RazorEngine.Core/Compilation/DirectCompilerServiceBase.cs @@ -1,4 +1,6 @@ -namespace RazorEngine.Compilation +using RazorEngine.Configuration; + +namespace RazorEngine.Compilation { using System; using System.CodeDom; @@ -41,8 +43,8 @@ public abstract class DirectCompilerServiceBase : CompilerServiceBase /// The code dom provider used to generate code. /// The markup parser factory. [SecurityCritical] - protected DirectCompilerServiceBase(RazorCodeLanguage codeLanguage, CodeDomProvider codeDomProvider, Func markupParserFactory) - : base(codeLanguage, new ParserBaseCreator(markupParserFactory)) + protected DirectCompilerServiceBase(RazorCodeLanguage codeLanguage, CodeDomProvider codeDomProvider, Func markupParserFactory, ITemplateServiceConfiguration config) + : base(codeLanguage, new ParserBaseCreator(markupParserFactory), config) { _codeDomProvider = codeDomProvider; } @@ -91,7 +93,7 @@ private Tuple Compile(TypeContext context) GenerateExecutable = false, IncludeDebugInformation = Debug, TreatWarningsAsErrors = false, - TempFiles = new TempFileCollection(GetTemporaryDirectory(), true), + TempFiles = new TempFileCollection(GetTemporaryDirectory(_config), true), CompilerOptions = string.Format("/target:library /optimize /define:RAZORENGINE {0}", haveMscorlib ? "/nostdlib" : "") diff --git a/src/source/RazorEngine.Core/Compilation/ICompilerServiceFactory.cs b/src/source/RazorEngine.Core/Compilation/ICompilerServiceFactory.cs index 45b84a94..8117dba9 100644 --- a/src/source/RazorEngine.Core/Compilation/ICompilerServiceFactory.cs +++ b/src/source/RazorEngine.Core/Compilation/ICompilerServiceFactory.cs @@ -1,4 +1,6 @@ using System.Security; +using RazorEngine.Configuration; + namespace RazorEngine.Compilation { /// @@ -13,6 +15,13 @@ public interface ICompilerServiceFactory /// The . /// An instance of . ICompilerService CreateCompilerService(Language language); + + /// + /// Creates a that supports the specified language. + /// + /// The . + /// An instance of . + ICompilerService CreateCompilerService(Language language, ITemplateServiceConfiguration config); #endregion } } diff --git a/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceBase.cs b/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceBase.cs index fbc7d7ad..93993895 100644 --- a/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceBase.cs +++ b/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceBase.cs @@ -19,6 +19,7 @@ using System.Security; using System.Security.Permissions; using Microsoft.CodeAnalysis.Emit; +using RazorEngine.Configuration; namespace RazorEngine.Roslyn.CSharp @@ -153,7 +154,18 @@ public override string ResolveReference(string path, string baseFilePath) /// [SecuritySafeCritical] public RoslynCompilerServiceBase(RazorCodeLanguage codeLanguage, Func markupParserFactory) - : base(codeLanguage, new ParserBaseCreator(markupParserFactory)) + : this(codeLanguage, markupParserFactory, null) + { + + } + + /// + /// Creates a new instance of the class. + /// + /// + /// + public RoslynCompilerServiceBase(RazorCodeLanguage codeLanguage, Func markupParserFactory, ITemplateServiceConfiguration config) + : base(codeLanguage, new ParserBaseCreator(markupParserFactory), config) { } @@ -202,7 +214,7 @@ public override Tuple CompileType(TypeContext context) var assemblyName = GetAssemblyName(context); (new PermissionSet(PermissionState.Unrestricted)).Assert(); - var tempDir = GetTemporaryDirectory(); + var tempDir = GetTemporaryDirectory(_config); var sourceCodeFile = Path.Combine(tempDir, String.Format("{0}.{1}", assemblyName, SourceFileExtension)); File.WriteAllText(sourceCodeFile, sourceCode); diff --git a/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceFactory.cs b/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceFactory.cs index 6dc07911..14f36340 100644 --- a/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceFactory.cs +++ b/src/source/RazorEngine.Core/Compilation/RoslynCompilerServiceFactory.cs @@ -7,6 +7,7 @@ using System.Security; using System.Text; using System.Threading.Tasks; +using RazorEngine.Configuration; namespace RazorEngine.Roslyn { @@ -25,18 +26,30 @@ public class RoslynCompilerServiceFactory : ICompilerServiceFactory [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] [SecuritySafeCritical] public ICompilerService CreateCompilerService(Language language) + { + return CreateCompilerService(language, null); + } + + /// + /// Creates a that supports the specified language. + /// + /// The . + /// An instance of . + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SecuritySafeCritical] + public ICompilerService CreateCompilerService(Language language, ITemplateServiceConfiguration config) { switch (language) { case Language.CSharp: - return new CSharpRoslynCompilerService(); + return new CSharpRoslynCompilerService(config: config); case Language.VisualBasic: -//#if RAZOR4 + //#if RAZOR4 throw new NotSupportedException("Razor4 doesn't support VB.net apparently."); -//#else -// return new VBRoslynCompilerService(); -//#endif + //#else + // return new VBRoslynCompilerService(config: config); + //#endif default: throw new ArgumentException("Unsupported language: " + language); diff --git a/src/source/RazorEngine.Core/Compilation/VisualBasic/VBDirectCompilerService.cs b/src/source/RazorEngine.Core/Compilation/VisualBasic/VBDirectCompilerService.cs index ad58b478..7da47f95 100644 --- a/src/source/RazorEngine.Core/Compilation/VisualBasic/VBDirectCompilerService.cs +++ b/src/source/RazorEngine.Core/Compilation/VisualBasic/VBDirectCompilerService.cs @@ -1,4 +1,6 @@ -namespace RazorEngine.Compilation.VisualBasic +using RazorEngine.Configuration; + +namespace RazorEngine.Compilation.VisualBasic { #if !RAZOR4 // no support for VB.net in Razor4? using System; @@ -26,11 +28,11 @@ public class VBDirectCompilerService : DirectCompilerServiceBase /// The markup parser to use. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed in base class: DirectCompilerServiceBase")] [SecurityCritical] - public VBDirectCompilerService(bool strictMode = true, Func markupParserFactory = null) + public VBDirectCompilerService(bool strictMode = true, Func markupParserFactory = null, ITemplateServiceConfiguration config = null) : base( new VBRazorCodeLanguage(strictMode), new VBCodeProvider(), - markupParserFactory) { } + markupParserFactory, config) { } #endregion /// diff --git a/src/source/RazorEngine.Core/Configuration/Fluent/FluentTemplateServiceConfiguration.cs b/src/source/RazorEngine.Core/Configuration/Fluent/FluentTemplateServiceConfiguration.cs index 1f403383..520ddc21 100644 --- a/src/source/RazorEngine.Core/Configuration/Fluent/FluentTemplateServiceConfiguration.cs +++ b/src/source/RazorEngine.Core/Configuration/Fluent/FluentTemplateServiceConfiguration.cs @@ -156,6 +156,12 @@ public ITemplateManager TemplateManager { get { return _innerConfig.TemplateManager; } } + + /// + /// Gets the Temporary Directory. + /// + public string TemporaryDirectory { get { return _innerConfig.TemporaryDirectory; } } + #endregion } } \ No newline at end of file diff --git a/src/source/RazorEngine.Core/Configuration/ITemplateServiceConfiguration.cs b/src/source/RazorEngine.Core/Configuration/ITemplateServiceConfiguration.cs index 96763332..49eaa8ed 100644 --- a/src/source/RazorEngine.Core/Configuration/ITemplateServiceConfiguration.cs +++ b/src/source/RazorEngine.Core/Configuration/ITemplateServiceConfiguration.cs @@ -95,6 +95,11 @@ public interface ITemplateServiceConfiguration /// Gets the template resolver. /// ITemplateManager TemplateManager { get; } + + /// + /// Sets the Temporary Directory where temp files will be written. + /// + string TemporaryDirectory { get; } #endregion } diff --git a/src/source/RazorEngine.Core/Configuration/RazorEngineConfigurationSection.cs b/src/source/RazorEngine.Core/Configuration/RazorEngineConfigurationSection.cs index 9b00a175..3f1e0266 100644 --- a/src/source/RazorEngine.Core/Configuration/RazorEngineConfigurationSection.cs +++ b/src/source/RazorEngine.Core/Configuration/RazorEngineConfigurationSection.cs @@ -22,6 +22,7 @@ public class RazorEngineConfigurationSection : ConfigurationSection private const string CachingProviderAttribute = "cachingProviderType"; private const string ReferenceResolverAttribute = "referenceResolverType"; private const string TemplateServicesElement = "templateServices"; + private const string TemporaryDirectoryAttribute = "temporaryDirectory"; #endregion #region Properties @@ -115,6 +116,14 @@ public TemplateServiceConfigurationElementCollection TemplateServices { get { return (TemplateServiceConfigurationElementCollection)this[TemplateServicesElement]; } } + /// + /// Sets the location of the temporary directory where temp files will be written. + /// + [ConfigurationProperty(TemporaryDirectoryAttribute, IsRequired = false)] + public string TemporaryDirectory + { + get { return (string) this[TemporaryDirectoryAttribute]; } + } #endregion #region Methods diff --git a/src/source/RazorEngine.Core/Configuration/ReadOnlyTemplateServiceConfiguration.cs b/src/source/RazorEngine.Core/Configuration/ReadOnlyTemplateServiceConfiguration.cs index 121db54f..b9135d5d 100644 --- a/src/source/RazorEngine.Core/Configuration/ReadOnlyTemplateServiceConfiguration.cs +++ b/src/source/RazorEngine.Core/Configuration/ReadOnlyTemplateServiceConfiguration.cs @@ -34,6 +34,7 @@ public class ReadOnlyTemplateServiceConfiguration : ITemplateServiceConfiguratio [Obsolete("Use TemplateManager instead")] private readonly ITemplateResolver _resolver; private readonly ITemplateManager _templateManager; + private readonly string _temporaryDirectory; /// /// Create a new readonly view (and copy) of the given configuration. @@ -122,6 +123,7 @@ public ReadOnlyTemplateServiceConfiguration(ITemplateServiceConfiguration config } #pragma warning restore 0618 // Backwards Compat. + _temporaryDirectory = config.TemporaryDirectory; } /// @@ -288,5 +290,12 @@ public ITemplateManager TemplateManager return _templateManager; } } + /// + /// Gets the temporary directory + /// + public string TemporaryDirectory + { + get { return _temporaryDirectory; } + } } } diff --git a/src/source/RazorEngine.Core/Configuration/TemplateServiceConfiguration.cs b/src/source/RazorEngine.Core/Configuration/TemplateServiceConfiguration.cs index eb70123b..b626cd0b 100644 --- a/src/source/RazorEngine.Core/Configuration/TemplateServiceConfiguration.cs +++ b/src/source/RazorEngine.Core/Configuration/TemplateServiceConfiguration.cs @@ -162,6 +162,12 @@ public ITemplateResolver Resolver { /// Gets or sets the template resolver. /// public ITemplateManager TemplateManager { get; set; } + + /// + /// Gets or sets the temporary directory. + /// + public string TemporaryDirectory { get; set; } + #endregion } } \ No newline at end of file diff --git a/src/source/RazorEngine.Core/Configuration/Xml/XmlTemplateServiceConfiguration.cs b/src/source/RazorEngine.Core/Configuration/Xml/XmlTemplateServiceConfiguration.cs index b853e58b..9ddda29c 100644 --- a/src/source/RazorEngine.Core/Configuration/Xml/XmlTemplateServiceConfiguration.cs +++ b/src/source/RazorEngine.Core/Configuration/Xml/XmlTemplateServiceConfiguration.cs @@ -113,6 +113,9 @@ public XmlTemplateServiceConfiguration(string name) /// Gets the template resolver. /// public ITemplateManager TemplateManager { get; private set; } + + public string TemporaryDirectory { get; private set; } + #endregion #region Methods @@ -196,6 +199,9 @@ private void InitialiseConfiguration(RazorEngineConfigurationSection config, Tem // Set whether we load templates with Assembly.Load(byte[]). DisableTempFileLocking = config.DisableTempFileLocking; + // Sets the tempoaryDirectory + TemporaryDirectory = config.TemporaryDirectory; + // Add the global namespaces. AddNamespaces(config.Namespaces); diff --git a/src/source/RazorEngine.Core/Templating/RazorEngineCore.cs b/src/source/RazorEngine.Core/Templating/RazorEngineCore.cs index e4dc9794..2598cb04 100644 --- a/src/source/RazorEngine.Core/Templating/RazorEngineCore.cs +++ b/src/source/RazorEngine.Core/Templating/RazorEngineCore.cs @@ -111,7 +111,7 @@ public virtual Tuple CreateTemplateType(ITemplateSource r foreach (string ns in _config.Namespaces) context.Namespaces.Add(ns); - using (var service = _config.CompilerServiceFactory.CreateCompilerService(_config.Language)) + using (var service = _config.CompilerServiceFactory.CreateCompilerService(_config.Language, _config)) { service.Debug = _config.Debug; service.DisableTempFileLocking = _config.DisableTempFileLocking;