diff --git a/Mono.TextTemplating.Roslyn/Mono.TextTemplating.Roslyn.csproj b/Mono.TextTemplating.Roslyn/Mono.TextTemplating.Roslyn.csproj
index 40f813a..892551f 100644
--- a/Mono.TextTemplating.Roslyn/Mono.TextTemplating.Roslyn.csproj
+++ b/Mono.TextTemplating.Roslyn/Mono.TextTemplating.Roslyn.csproj
@@ -27,15 +27,23 @@ To enable the in-process C# compiler, use the TemplatingEngine.UseInProcessCompi
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
+
+
+
+
+
diff --git a/Mono.TextTemplating.Tests/DummyHost.cs b/Mono.TextTemplating.Tests/DummyHost.cs
index 86da60f..93358d8 100644
--- a/Mono.TextTemplating.Tests/DummyHost.cs
+++ b/Mono.TextTemplating.Tests/DummyHost.cs
@@ -27,7 +27,7 @@
using System;
using System.Collections.Generic;
using System.CodeDom.Compiler;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
namespace Mono.TextTemplating.Tests
{
@@ -37,11 +37,11 @@ public class DummyHost : ITextTemplatingEngineHost
public readonly Dictionary Locations = new Dictionary ();
public readonly Dictionary Contents = new Dictionary ();
public readonly Dictionary HostOptions = new Dictionary ();
- List standardAssemblyReferences = new List ();
+ List standardAssemblyReferences = new List (new[] { typeof(TemplatingEngine).Assembly.Location });
List standardImports = new List ();
public readonly CompilerErrorCollection Errors = new CompilerErrorCollection ();
public readonly Dictionary DirectiveProcessors = new Dictionary ();
-
+ public readonly Dictionary Parameters = new Dictionary ();
public virtual object GetHostOption (string optionName)
{
object o;
@@ -68,7 +68,7 @@ public virtual AppDomain ProvideTemplatingAppDomain (string content)
public virtual string ResolveAssemblyReference (string assemblyReference)
{
- throw new System.NotImplementedException();
+ return assemblyReference;
}
public virtual Type ResolveDirectiveProcessor (string processorName)
@@ -80,22 +80,24 @@ public virtual Type ResolveDirectiveProcessor (string processorName)
public virtual string ResolveParameterValue (string directiveId, string processorName, string parameterName)
{
- throw new System.NotImplementedException();
+ return Parameters[parameterName];
}
public virtual string ResolvePath (string path)
{
throw new System.NotImplementedException();
}
-
+
+ string extension;
+
public virtual void SetFileExtension (string extension)
{
- throw new System.NotImplementedException();
+ this.extension = extension;
}
public virtual void SetOutputEncoding (System.Text.Encoding encoding, bool fromOutputDirective)
{
- throw new System.NotImplementedException();
+
}
public virtual IList StandardAssemblyReferences {
diff --git a/Mono.TextTemplating.Tests/GenerationTests.cs b/Mono.TextTemplating.Tests/GenerationTests.cs
index fb5038a..dc76f6d 100644
--- a/Mono.TextTemplating.Tests/GenerationTests.cs
+++ b/Mono.TextTemplating.Tests/GenerationTests.cs
@@ -28,9 +28,10 @@
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
using System.Linq;
using System.CodeDom.Compiler;
+using System.Reflection;
namespace Mono.TextTemplating.Tests
{
@@ -48,6 +49,60 @@ public void TemplateGeneratorTest ()
Assert.IsNull (gen.Errors.OfType ().FirstOrDefault (), "ProcessTemplate");
}
+ [Test]
+ public void GenerateStaticPropertyForParameter ()
+ {
+ var engine = new TemplatingEngine ();
+
+ var host = new DummyHost ();
+
+ var output = engine.PreprocessTemplate (T4ParameterSample, host, "ParameterTestClass", "Testing", out string language, out string[] references);
+
+ foreach (CompilerError error in host.Errors) {
+ Console.Error.WriteLine (error.ErrorText);
+ }
+
+ Assert.IsTrue (output.Contains ("public static string TestParameter"));
+
+ Console.Out.WriteLine (output);
+ }
+
+ [Test]
+ [TestCase("some nonsense value")]
+ public void GenerateStaticPropertyForParameterCanInitilialize (string value)
+ {
+ var engine = new TemplatingEngine ();
+
+ var host = new DummyHost () {
+ TemplateFile = "test.tt"
+ };
+
+ host.Parameters.Add ("TestParameter", value);
+
+
+ var tt = engine.CompileTemplate (T4ParameterSample, host);
+
+ foreach (CompilerError error in host.Errors) {
+ Console.Error.WriteLine (error.ErrorText);
+ }
+
+ Type ttType = tt.textTransformation?.GetType ();
+
+ Assert.IsNotNull (ttType);
+
+ var initMethod = ttType.GetMethod ("Initialize");
+ var testAssignment = ttType.GetMethod ("TestAssignment");
+ var parameter = ttType.GetProperty ("TestParameter", BindingFlags.Public | BindingFlags.Static);
+
+ initMethod.Invoke (tt.textTransformation, null);
+
+ if (testAssignment.Invoke(tt.textTransformation, null) is bool success) {
+ Assert.IsTrue (success);
+ }
+
+ Assert.AreEqual (value, parameter.GetValue (null));
+ }
+
[Test]
public void ImportReferencesTest ()
{
@@ -105,6 +160,8 @@ public void GenerateWindowsNewlines ()
Generate (WinInput, WinOutput, "\r\n");
}
+
+
[Test]
public void DefaultLanguage ()
{
@@ -121,7 +178,7 @@ public void DefaultLanguage ()
void Generate (string input, string expectedOutput, string newline)
{
var host = new DummyHost ();
- string nameSpaceName = "Microsoft.VisualStudio.TextTemplating4f504ca0";
+ string nameSpaceName = "Mono.VisualStudio.TextTemplating4f504ca0";
string code = GenerateCode (host, input, nameSpaceName, newline);
Assert.AreEqual (0, host.Errors.Count);
@@ -164,14 +221,28 @@ string GenerateCode (ITextTemplatingEngineHost host, string content, string name
#endregion
+ #region input strings
+ public const string T4ParameterSample =
+@"<#@ template hostspecific=""true"" language=""C#"" #>
+<#@ output extension="".cs"" #>
+<#@ parameter type=""System.String"" name=""TestParameter"" #>
+<#@ import namespace=""System"" #>
+using System;
+<#+
+public bool TestAssignment() {
+ return !string.IsNullOrEmpty(TestParameter);
+}
+#>";
+ #endregion
+
#region Expected output strings
public static string OutputSample1 =
@"
-namespace Microsoft.VisualStudio.TextTemplating4f504ca0 {
+namespace Mono.VisualStudio.TextTemplating4f504ca0 {
- public partial class GeneratedTextTransformation : global::Microsoft.VisualStudio.TextTemplating.TextTransformation {
+ public partial class GeneratedTextTransformation : global::Mono.VisualStudio.TextTemplating.TextTransformation {
#line 9 """"
@@ -205,7 +276,7 @@ public override string TransformText() {
#line hidden
#line 7 """"
- this.Write(global::Microsoft.VisualStudio.TextTemplating.ToStringHelper.ToStringWithCulture( bar ));
+ this.Write(global::Mono.VisualStudio.TextTemplating.ToStringHelper.ToStringWithCulture( bar ));
#line default
#line hidden
diff --git a/Mono.TextTemplating.Tests/Mono.TextTemplating.Tests.csproj b/Mono.TextTemplating.Tests/Mono.TextTemplating.Tests.csproj
index 7a0d11b..7998921 100644
--- a/Mono.TextTemplating.Tests/Mono.TextTemplating.Tests.csproj
+++ b/Mono.TextTemplating.Tests/Mono.TextTemplating.Tests.csproj
@@ -8,8 +8,15 @@
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
-
+
+
+
+
diff --git a/Mono.TextTemplating.Tests/TemplateEnginePreprocessTemplateTests.cs b/Mono.TextTemplating.Tests/TemplateEnginePreprocessTemplateTests.cs
index 86b170d..fef001d 100644
--- a/Mono.TextTemplating.Tests/TemplateEnginePreprocessTemplateTests.cs
+++ b/Mono.TextTemplating.Tests/TemplateEnginePreprocessTemplateTests.cs
@@ -29,7 +29,7 @@
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
namespace Mono.TextTemplating.Tests
{
diff --git a/Mono.TextTemplating.Tests/TextTemplatingSessionTests.cs b/Mono.TextTemplating.Tests/TextTemplatingSessionTests.cs
index 1c7c5a8..405e953 100644
--- a/Mono.TextTemplating.Tests/TextTemplatingSessionTests.cs
+++ b/Mono.TextTemplating.Tests/TextTemplatingSessionTests.cs
@@ -1,4 +1,4 @@
-//
+//
// TextTemplatingSessionTests.cs
//
// Author:
@@ -26,7 +26,7 @@
using System;
using System.Reflection;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
using NUnit.Framework;
namespace Mono.TextTemplating.Tests
diff --git a/Mono.TextTemplating.sln b/Mono.TextTemplating.sln
index d6a1007..847a0df 100644
--- a/Mono.TextTemplating.sln
+++ b/Mono.TextTemplating.sln
@@ -1,11 +1,12 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.TextTemplating", "Mono.TextTemplating\Mono.TextTemplating.csproj", "{A2364D6A-00EF-417C-80A6-815726C70032}"
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30320.27
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.TextTemplating", "Mono.TextTemplating\Mono.TextTemplating.csproj", "{A2364D6A-00EF-417C-80A6-815726C70032}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.TextTemplating.Tests", "Mono.TextTemplating.Tests\Mono.TextTemplating.Tests.csproj", "{CB590106-8331-4CBE-8131-B154E7BF79E1}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.TextTemplating.Tests", "Mono.TextTemplating.Tests\Mono.TextTemplating.Tests.csproj", "{CB590106-8331-4CBE-8131-B154E7BF79E1}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextTransform", "TextTransform\TextTransform.csproj", "{D1D35409-C814-47F6-B038-B9B5BF0FE490}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextTransform", "TextTransform\TextTransform.csproj", "{D1D35409-C814-47F6-B038-B9B5BF0FE490}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EEE624A1-0ED3-4D57-96B4-5D1B22E72697}"
ProjectSection(SolutionItems) = preProject
@@ -13,11 +14,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-t4", "dotnet-t4\dotnet-t4.csproj", "{6AA924D8-7119-4593-9B56-11D17AC3578E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-t4", "dotnet-t4\dotnet-t4.csproj", "{6AA924D8-7119-4593-9B56-11D17AC3578E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-t4-project-tool", "dotnet-t4-project-tool\dotnet-t4-project-tool.csproj", "{114B7AEF-61DA-453A-9A84-6DDEA13460B7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-t4-project-tool", "dotnet-t4-project-tool\dotnet-t4-project-tool.csproj", "{114B7AEF-61DA-453A-9A84-6DDEA13460B7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.TextTemplating.Roslyn", "Mono.TextTemplating.Roslyn\Mono.TextTemplating.Roslyn.csproj", "{8DB780A9-27C1-44B4-860F-50C4419FD349}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.TextTemplating.Roslyn", "Mono.TextTemplating.Roslyn\Mono.TextTemplating.Roslyn.csproj", "{8DB780A9-27C1-44B4-860F-50C4419FD349}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Engine.cs b/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Engine.cs
index fd78b49..6af95ff 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Engine.cs
+++ b/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Engine.cs
@@ -26,11 +26,13 @@
using System;
using Mono.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
namespace Microsoft.VisualStudio.TextTemplating
{
- [Obsolete ("Use Mono.TextTemplating.TemplatingEngine directly")]
- public class Engine : ITextTemplatingEngine
+ [Obsolete ("Use Mono.TextTemplating.TemplatingEngine directly", true)]
+ public class Engine
+ : ITextTemplatingEngine
{
TemplatingEngine engine = new TemplatingEngine ();
@@ -44,7 +46,7 @@ public string PreprocessTemplate (string content, ITextTemplatingEngineHost host
{
return engine.PreprocessTemplate (content, host, className, classNamespace, out language, out references);
}
-
+
public const string CacheAssembliesOptionString = "CacheAssemblies";
}
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/AssemblyResolver.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/AssemblyResolver.cs
index 5e3145f..19648d2 100644
--- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/AssemblyResolver.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/AssemblyResolver.cs
@@ -42,7 +42,7 @@ IEnumerable GetImplicitReferences ()
{
yield return "mscorlib.dll";
yield return "netstandard.dll";
-
+
if (runtime.Kind == RuntimeKind.NetCore) {
yield return "System.Runtime.dll";
//because we're referencing the impl not the ref asms, we end up
diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CscCodeCompiler.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CscCodeCompiler.cs
index 52c1b2f..f2809c4 100644
--- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CscCodeCompiler.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CscCodeCompiler.cs
@@ -32,6 +32,7 @@
using System.Threading.Tasks;
using System.Linq;
using System.Text;
+using System.Globalization;
namespace Mono.TextTemplating.CodeCompilation
{
@@ -115,85 +116,96 @@ public override async Task CompileFile (CodeCompilerArgument
UseShellExecute = false
};
- if (log != null) {
- log.WriteLine ($"{psi.FileName} {psi.Arguments}");
- }
-
if (runtime.Kind == RuntimeKind.NetCore) {
psi.Arguments = $"\"{psi.FileName}\" {psi.Arguments}";
psi.FileName = Path.GetFullPath (Path.Combine (runtime.RuntimeDir, "..", "..", "..", "dotnet"));
}
- var stdout = new StringWriter ();
- var stderr = new StringWriter ();
-
- TextWriter outWriter = stderr, errWriter = stderr;
- if (log != null) {
- outWriter = new SplitOutputWriter (log, outWriter);
- errWriter = new SplitOutputWriter (log, errWriter);
+ if (log != null)
+ {
+ log.WriteLine($"{psi.FileName} {psi.Arguments}");
+ log.WriteLine ("-------------------------------------------------------------------------------");
}
- var process = ProcessUtils.StartProcess (psi, outWriter, errWriter, token);
+ using (var stdout = new StringWriter (new StringBuilder(), CultureInfo.CurrentCulture))
+ using (var stderr = new StringWriter (new StringBuilder (), CultureInfo.CurrentCulture))
+ using (TextWriter outWriter = log != null ? new SplitOutputWriter (log, stderr) : (TextWriter)stderr)
+ using (TextWriter errWriter = log != null ? new SplitOutputWriter (log, stderr) : (TextWriter)stderr) {
- var result = await process;
+ var process = ProcessUtils.StartProcess (psi, outWriter, errWriter, token);
- var outputList = new List ();
- var errors = new List ();
+ int result = -1;
- void ConsumeOutput (string s)
- {
- using (var sw = new StringReader (s)) {
- string line;
- while ((line = sw.ReadLine ()) != null) {
- outputList.Add (line);
- var err = MSBuildErrorParser.TryParseLine (line);
- if (err != null) {
- errors.Add (err);
+ if (!token.IsCancellationRequested) {
+ result = await process.ConfigureAwait (false);
+ }
+
+ var outputList = new List ();
+ var errors = new List ();
+
+ void ConsumeOutput (string s)
+ {
+ using (var sw = new StringReader (s)) {
+ string line;
+ while ((line = sw.ReadLine ()) != null) {
+ outputList.Add (line);
+ var err = MSBuildErrorParser.TryParseLine (line);
+ if (err != null) {
+ errors.Add (err);
+ }
}
}
}
- }
- ConsumeOutput (stdout.ToString ());
- ConsumeOutput (stderr.ToString ());
+ ConsumeOutput (stdout.ToString ());
+ ConsumeOutput (stderr.ToString ());
- if (log != null) {
- log.WriteLine ($"{psi.FileName} {psi.Arguments}");
- }
+ if (log != null) {
+ log.WriteLine ();
+ log.WriteLine ();
+ log.WriteLine ($"{psi.FileName} {psi.Arguments}");
+ }
- return new CodeCompilerResult {
- Success = result == 0,
- Errors = errors,
- ExitCode = result,
- Output = outputList,
- ResponseFile = rspPath
- };
+ return new CodeCompilerResult {
+ Success = result == 0,
+ Errors = errors,
+ ExitCode = result,
+ Output = outputList,
+ ResponseFile = rspPath
+ };
+ }
}
//we know that ProcessUtils.StartProcess only uses WriteLine and Write(string)
class SplitOutputWriter : TextWriter
{
- readonly TextWriter a;
- readonly TextWriter b;
+ readonly TextWriter logWriter;
+ readonly TextWriter errorWriter;
public SplitOutputWriter (TextWriter a, TextWriter b)
{
- this.a = a;
- this.b = b;
+ this.logWriter = a;
+ this.errorWriter = b;
}
public override Encoding Encoding => Encoding.UTF8;
public override void WriteLine ()
{
- a.WriteLine ();
- b.WriteLine ();
+ logWriter.WriteLine ();
+ errorWriter.WriteLine ();
+ }
+
+ public override void WriteLine (string value)
+ {
+ logWriter.WriteLine (value);
+ errorWriter.WriteLine (value);
}
public override void Write (string value)
{
- a.Write (value);
- b.Write (value);
+ logWriter.Write (value);
+ errorWriter.Write (value);
}
}
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/ProcessUtils.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/ProcessUtils.cs
index b285b76..00ad60e 100644
--- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/ProcessUtils.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/ProcessUtils.cs
@@ -57,9 +57,11 @@ public static Task StartProcess (ProcessStartInfo psi, TextWriter stdout, T
if (!p.HasExited) {
p.Kill ();
}
- } catch (InvalidOperationException ex) {
- if (ex.Message.IndexOf ("already exited", StringComparison.Ordinal) < 0)
+ }
+ catch (InvalidOperationException ex) {
+ if (ex.Message.IndexOf ("already exited", StringComparison.Ordinal) < 0) {
throw;
+ }
}
});
}
@@ -75,16 +77,19 @@ public static Task StartProcess (ProcessStartInfo psi, TextWriter stdout, T
try {
if (e.Data == null) {
outputDone = true;
- if (exitDone && errorDone)
+ if (exitDone && errorDone) {
tcs.TrySetResult (p.ExitCode);
+ }
return;
}
- if (stdOutInitialized)
+ if (stdOutInitialized) {
stdout.WriteLine ();
+ }
stdout.Write (e.Data);
stdOutInitialized = true;
- } catch (Exception ex) {
+ }
+ catch (Exception ex) {
tcs.TrySetException (ex);
}
};
@@ -99,16 +104,19 @@ public static Task StartProcess (ProcessStartInfo psi, TextWriter stdout, T
try {
if (e.Data == null) {
errorDone = true;
- if (exitDone && outputDone)
+ if (exitDone && outputDone) {
tcs.TrySetResult (p.ExitCode);
+ }
return;
}
- if (stdErrInitialized)
+ if (stdErrInitialized) {
stderr.WriteLine ();
+ }
stderr.Write (e.Data);
stdErrInitialized = true;
- } catch (Exception ex) {
+ }
+ catch (Exception ex) {
tcs.TrySetException (ex);
}
};
@@ -119,8 +127,9 @@ public static Task StartProcess (ProcessStartInfo psi, TextWriter stdout, T
p.Exited += (sender, e) => {
exitDone = true;
- if (errorDone && outputDone)
+ if (errorDone && outputDone) {
tcs.TrySetResult (p.ExitCode);
+ }
};
return tcs.Task;
diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs
index d64b5d6..d2ab001 100644
--- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs
@@ -30,11 +30,16 @@
namespace Mono.TextTemplating.CodeCompilation
{
- enum RuntimeKind
+ public enum RuntimeKind
{
+#if !NET5
+ Default = 0,
NetCore,
NetFramework,
Mono
+#else
+ Net
+#endif
}
class RuntimeInfo
@@ -49,18 +54,18 @@ class RuntimeInfo
public string CscPath { get; private set; }
public bool IsValid => Error == null;
- public static RuntimeInfo GetRuntime ()
+ public static RuntimeInfo GetRuntime (RuntimeKind kind = RuntimeKind.Default)
{
var monoFx = GetMonoRuntime ();
- if (monoFx.IsValid) {
+ if (monoFx.IsValid && (monoFx.Kind == kind || kind == RuntimeKind.Default)) {
return monoFx;
}
var netFx = GetNetFrameworkRuntime ();
- if (netFx.IsValid) {
+ if (netFx.IsValid && (netFx.Kind == kind || kind == RuntimeKind.Default)) {
return netFx;
}
var coreFx = GetDotNetCoreRuntime ();
- if (coreFx.IsValid) {
+ if (coreFx.IsValid && (coreFx.Kind == kind || kind == RuntimeKind.Default)) {
return coreFx;
}
return FromError (RuntimeKind.Mono, "Could not find any valid runtime" );
@@ -97,6 +102,27 @@ public static RuntimeInfo GetNetFrameworkRuntime ()
};
}
+ public static RuntimeInfo GetDotNetCoreRuntime ()
+ {
+ var dotnetRoot = FindDotNetRoot ();
+ if (dotnetRoot == null) {
+ return FromError (RuntimeKind.NetCore, "Could not find .NET Core installation");
+ }
+
+ string MakeCscPath (string d) => Path.Combine (d, "Roslyn", "bincore", "csc.dll");
+ var sdkDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "sdk"), d => File.Exists (MakeCscPath (d)));
+ if (sdkDir == null) {
+ return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK");
+ }
+
+ var runtimeDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "shared", "Microsoft.NETCore.App"), d => File.Exists (Path.Combine (d, "System.Runtime.dll")));
+ if (runtimeDir == null) {
+ return FromError (RuntimeKind.NetCore, "Could not find System.Runtime.dll in any .NET shared runtime");
+ }
+
+ return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, CscPath = MakeCscPath (sdkDir) };
+ }
+
static string FindDotNetRoot ()
{
string dotnetRoot;
@@ -144,25 +170,6 @@ static string FindHighestVersionedDirectory (string parentFolder, Func Path.Combine (d, "Roslyn", "bincore", "csc.dll");
- var sdkDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "sdk"), d => File.Exists (MakeCscPath (d)));
- if (sdkDir == null) {
- return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK" );
- }
-
- var runtimeDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "shared", "Microsoft.NETCore.App"), d => File.Exists (Path.Combine (d, "System.Runtime.dll")));
- if (runtimeDir == null) {
- return FromError (RuntimeKind.NetCore, "Could not find System.Runtime.dll in any .NET shared runtime" );
- }
-
- return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, CscPath = MakeCscPath (sdkDir) };
- }
+
}
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating.csproj b/Mono.TextTemplating/Mono.TextTemplating.csproj
index 5034720..5401e2f 100644
--- a/Mono.TextTemplating/Mono.TextTemplating.csproj
+++ b/Mono.TextTemplating/Mono.TextTemplating.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0;net45;net35
true
@@ -25,10 +25,44 @@ This package allows embedding the T4 engine in an application.
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
+
+
+
+
+
+ 4.3.0
+
+
+ 4.3.0
+
+
+
+
+
+ VsTemplatingErrorResources.resx
+ True
+ True
+
+
+
+
+
+ VsTemplatingErrorResources.Designer.cs
+ ResXFileCodeGenerator
+
+
+
+
+
+ 4.3.0
+
\ No newline at end of file
diff --git a/Mono.TextTemplating/Mono.TextTemplating/CompiledTemplate.cs b/Mono.TextTemplating/Mono.TextTemplating/CompiledTemplate.cs
index 3760f9f..6ebd294 100644
--- a/Mono.TextTemplating/Mono.TextTemplating/CompiledTemplate.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating/CompiledTemplate.cs
@@ -26,7 +26,7 @@
using System;
using System.Reflection;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
using System.CodeDom.Compiler;
using System.Globalization;
using System.Collections.Generic;
@@ -40,7 +40,7 @@ public sealed class CompiledTemplate :
IDisposable
{
ITextTemplatingEngineHost host;
- object textTransformation;
+ internal object textTransformation;
readonly CultureInfo culture;
readonly string [] assemblyFiles;
@@ -54,12 +54,19 @@ public CompiledTemplate (ITextTemplatingEngineHost host, CompilerResults results
Load (results, fullName);
}
+ ///
+ /// Get the compiled assembly
+ ///
+ public Assembly Assembly { get; private set; }
+
void Load (CompilerResults results, string fullName)
{
//results.CompiledAssembly doesn't work on .NET core, it throws a cryptic internal error
//use Assembly.LoadFile instead
- var assembly = System.Reflection.Assembly.LoadFile (results.PathToAssembly);
- Type transformType = assembly.GetType (fullName);
+ //for debugging we need the assembly
+ Assembly = System.Reflection.Assembly.LoadFile (results.PathToAssembly);
+
+ Type transformType = Assembly.GetType (fullName);
//MS Templating Engine does not look on the type itself,
//it checks only that required methods are exists in the compiled type
textTransformation = Activator.CreateInstance (transformType);
@@ -82,7 +89,13 @@ void Load (CompilerResults results, string fullName)
}
}
- public string Process ()
+
+ public string Process()
+ {
+ return Process (textTransformation);
+ }
+
+ public string Process (object textTransformation)
{
var ttType = textTransformation.GetType ();
diff --git a/Mono.TextTemplating/Mono.TextTemplating/DebugTextTemplateEngine.cs b/Mono.TextTemplating/Mono.TextTemplating/DebugTextTemplateEngine.cs
new file mode 100644
index 0000000..235b68b
--- /dev/null
+++ b/Mono.TextTemplating/Mono.TextTemplating/DebugTextTemplateEngine.cs
@@ -0,0 +1,145 @@
+using System;
+using Mono.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating.VSHost;
+
+namespace Mono.TextTemplating
+{
+ using System.Globalization;
+ using System.IO;
+ using System.Reflection;
+ using System.Runtime.Serialization;
+ using System.Threading;
+
+ public partial class TemplatingEngine
+ : IProcessTextTemplatingEngine
+ {
+ public IProcessTransformationRun PrepareTransformationRun (string content, ITextTemplatingEngineHost host, IProcessTransformationRunFactory runFactory, bool debugging = false)
+ {
+ if (content == null) {
+ throw new ArgumentNullException (nameof(content));
+ }
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+ if (runFactory == null) {
+ throw new ArgumentNullException (nameof (runFactory));
+ }
+
+ if (host is ITextTemplatingSessionHost sessionHost) {
+ if (sessionHost.Session == null) {
+ sessionHost.Session = sessionHost.CreateSession ();
+ }
+ }
+
+ ParsedTemplate pt = ParsedTemplate.FromText (content, host);
+
+ IProcessTransformationRun run = null;
+
+ try {
+ if (pt.Errors.HasErrors) {
+ return null;
+ }
+ TemplateSettings settings = GetSettings (host, pt);
+
+ settings.Debug = debugging;
+
+ run = CompileAndPrepareRun (pt, content, host, runFactory, settings);
+ } catch(Exception ex) {
+ if (IsCriticalException(ex)) {
+ throw;
+ }
+ pt.LogError (string.Format(CultureInfo.CurrentCulture, VsTemplatingErrorResources.ExceptionProcessingTemplate, ex), new Location (host.TemplateFile, -1, -1));
+ }
+ finally {
+ host.LogErrors (pt.Errors);
+ }
+
+ return run;
+ }
+
+ protected virtual IProcessTransformationRun CompileAndPrepareRun (ParsedTemplate pt, string content, ITextTemplatingEngineHost host, IProcessTransformationRunFactory runFactory, TemplateSettings settings)
+ {
+ TransformationRunner runner = null;
+ bool success = false;
+
+ if (pt == null) {
+ throw new ArgumentNullException (nameof (pt));
+ }
+
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+
+ if (runFactory == null) {
+ throw new ArgumentNullException (nameof (runFactory));
+ }
+
+ if (settings == null) {
+ throw new ArgumentNullException (nameof (settings));
+ }
+
+ Assembly ResolveReferencedAssemblies (object sender, ResolveEventArgs args)
+ {
+ AssemblyName asmName = new AssemblyName (args.Name);
+ foreach (var asmFile in settings.Assemblies) {
+ if (asmName.Name == Path.GetFileNameWithoutExtension (asmFile))
+ return Assembly.LoadFrom (asmFile);
+ }
+
+ var path = host.ResolveAssemblyReference (asmName.Name);
+
+ if (File.Exists (path)) {
+ return Assembly.LoadFrom (path);
+ }
+
+ return null;
+ }
+
+ try {
+ try {
+ if (runFactory.CreateTransformationRun (typeof (TransformationRunner), pt, new ResolveEventHandler(ResolveReferencedAssemblies)) is TransformationRunner theRunner) {
+ runner = theRunner;
+ }
+ }
+ catch (Exception ex) {
+ if (IsCriticalException (ex)) {
+ throw;
+ }
+ }
+ if (runner != null && !runner.Errors.HasErrors) {
+ ProcessReferences (host, pt, settings);
+ if (!pt.Errors.HasErrors) {
+ //with app domains dissappearing we may not be able to pre load anything
+ //runner.PreLoadAssemblies (settings.Assemblies);
+ try {
+ success = runner.PrepareTransformation (pt, content, settings.HostSpecific ? host : null, settings);
+ }
+ catch (SerializationException) {
+ pt.LogError (VsTemplatingErrorResources.SessionHostMarshalError, new Location (host.TemplateFile, -1, -1));
+ throw;
+ }
+ }
+ }
+ }
+ catch(Exception ex) {
+ if (IsCriticalException (ex)) {
+ throw;
+ }
+ pt.LogError (ex.ToString (), new Location (host.TemplateFile, -1, -1));
+ }
+ finally {
+ if (runner != null) {
+ pt.Errors.AddRange (runner.Errors);
+ runner.ClearErrors ();
+ }
+ }
+
+ return success ? runner : null;
+ }
+
+ public static bool IsCriticalException(Exception e)
+ {
+ return ((e is StackOverflowException) || ((e is OutOfMemoryException) || ((e is ThreadAbortException) || ((e.InnerException != null) && IsCriticalException (e.InnerException)))));
+ }
+ }
+}
diff --git a/Mono.TextTemplating/Mono.TextTemplating/ParsedTemplate.cs b/Mono.TextTemplating/Mono.TextTemplating/ParsedTemplate.cs
index 8248385..062662b 100644
--- a/Mono.TextTemplating/Mono.TextTemplating/ParsedTemplate.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating/ParsedTemplate.cs
@@ -28,7 +28,7 @@
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
namespace Mono.TextTemplating
{
@@ -66,6 +66,10 @@ public IEnumerable Content {
public static ParsedTemplate FromText (string content, ITextTemplatingEngineHost host)
{
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+
var template = new ParsedTemplate (host.TemplateFile);
try {
template.Parse (host, new Tokeniser (host.TemplateFile, content));
@@ -270,6 +274,9 @@ public Location (string fileName, int line, int column) : this()
Column = column;
Line = line;
}
+
+ public Location (string fileName)
+ : this (fileName, -1, -1) { }
public int Line { get; private set; }
public int Column { get; private set; }
@@ -289,5 +296,25 @@ public bool Equals (Location other)
{
return other.Line == Line && other.Column == Column && other.FileName == FileName;
}
+
+ public override bool Equals (object obj)
+ {
+ return obj is Location && Equals ((Location)obj);
+ }
+
+ public static bool operator == (Location left, Location right)
+ {
+ return left.Equals (right);
+ }
+
+ public static bool operator != (Location left, Location right)
+ {
+ return !(left == right);
+ }
+
+ public override int GetHashCode ()
+ {
+ return base.GetHashCode ();
+ }
}
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating/StringUtil.cs b/Mono.TextTemplating/Mono.TextTemplating/StringUtil.cs
index bfcadb5..b98c412 100644
--- a/Mono.TextTemplating/Mono.TextTemplating/StringUtil.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating/StringUtil.cs
@@ -1,4 +1,6 @@
using System;
+using System.ComponentModel;
+using System.Reflection;
namespace Mono.TextTemplating
{
@@ -14,5 +16,33 @@ public static Boolean IsNullOrWhiteSpace (String value)
return true;
}
+
+ public static TType GetValue(this PropertyInfo property, object @object, object[] index)
+ {
+ if (property.GetValue(@object, index) is TType success) {
+ return success;
+ }
+ return default;
+ }
+
+
+ public static bool TryParse (this string value, out TEnum @enum)
+ where TEnum: struct
+ {
+#if NET35
+ if (Enum.Parse (typeof (TEnum), value) is TEnum success) {
+ @enum = success;
+
+ return true;
+ }
+
+ @enum = default;
+
+ return false;
+#else
+ return Enum.TryParse (value, out @enum);
+#endif
+ }
+
}
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplateGenerator.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplateGenerator.cs
index 7ead97e..4c24063 100644
--- a/Mono.TextTemplating/Mono.TextTemplating/TemplateGenerator.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating/TemplateGenerator.cs
@@ -30,7 +30,8 @@
using System.IO;
using System.Reflection;
using System.Text;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
+using System.Runtime.Serialization;
namespace Mono.TextTemplating
{
@@ -508,5 +509,10 @@ public virtual IEnumerable GetAdditionalDirectiveProcessors
{
yield break;
}
+
+ public void GetObjectData (SerializationInfo info, StreamingContext context)
+ {
+ throw new NotImplementedException ();
+ }
}
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs
index cd3f318..7aa9f3f 100644
--- a/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs
@@ -27,8 +27,13 @@
using System;
using System.Text;
using System.Collections.Generic;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
using System.IO;
+using System.Reflection;
+using System.Threading;
+#if !NET35
+using Mono.TextTemplating.CodeCompilation;
+#endif
namespace Mono.TextTemplating
{
@@ -45,6 +50,11 @@ public TemplateSettings ()
public bool HostSpecific { get; set; }
public bool HostPropertyOnBase { get; set; }
public bool Debug { get; set; }
+ public bool CachedTemplates { get; set; }
+#if !NET35
+ public CancellationToken CancellationToken { get; set; }
+ public RuntimeKind RuntimeKind { get; set; }
+#endif
public TextWriter Log { get; set; }
public string Inherits { get; set; }
public string Name { get; set; }
@@ -61,10 +71,11 @@ public TemplateSettings ()
public Dictionary DirectiveProcessors { get; private set; }
public bool IncludePreprocessingHelpers { get; set; }
public bool IsPreprocessed { get; set; }
- public bool RelativeLinePragmas { get; set; }
+ public bool UseRelativeLinePragmas { get; set; }
public bool NoLinePragmas { get; set; }
public bool InternalVisibility { get; set; }
public Type HostType { get; set; }
+
public string GetFullName () => string.IsNullOrEmpty (Namespace) ? Name : Namespace + "." + Name;
}
diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs
index 781b4c7..960166b 100644
--- a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs
+++ b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs
@@ -34,14 +34,15 @@
using System.Text;
using System.Threading;
using Microsoft.CSharp;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
+using System.Globalization;
#if FEATURE_ROSLYN
using Mono.TextTemplating.CodeCompilation;
#endif
namespace Mono.TextTemplating
{
- public class TemplatingEngine :
+ public partial class TemplatingEngine :
#if FEATURE_APPDOMAINS
MarshalByRefObject,
#endif
@@ -60,10 +61,10 @@ internal void SetCompilerFunc (Func cr
createCompilerFunc = createCompiler;
}
- CodeCompilation.CodeCompiler GetOrCreateCompiler ()
+ CodeCompilation.CodeCompiler GetOrCreateCompiler (RuntimeKind kind = RuntimeKind.Default)
{
if (cachedCompiler == null) {
- var runtime = RuntimeInfo.GetRuntime ();
+ var runtime = RuntimeInfo.GetRuntime (kind);
if (runtime.Error != null) {
throw new Exception (runtime.Error);
}
@@ -238,7 +239,7 @@ CompilerResults CompileCode (IEnumerable references, TemplateSettings se
}
// this may throw, so do it before writing source files
- var compiler = GetOrCreateCompiler ();
+ var compiler = GetOrCreateCompiler (settings.RuntimeKind);
var tempFolder = Path.GetTempFileName ();
File.Delete (tempFolder);
@@ -259,7 +260,7 @@ CompilerResults CompileCode (IEnumerable references, TemplateSettings se
args.OutputPath = Path.Combine (tempFolder, settings.Name + ".dll");
args.TempDirectory = tempFolder;
- var result = compiler.CompileFile (args, settings.Log, CancellationToken.None).Result;
+ var result = compiler.CompileFile (args, settings.Log, settings.CancellationToken).Result;
var r = new CompilerResults (new TempFileCollection ());
r.TempFiles.AddFile (sourceFilename, false);
@@ -283,7 +284,12 @@ CompilerResults CompileCode (IEnumerable references, TemplateSettings se
}
if (!args.Debug) {
- r.TempFiles.Delete ();
+ if (r.TempFiles is IDisposable disposable) {
+ disposable.Dispose ();
+ }
+ }
+ else {
+ r.TempFiles.KeepFiles = args.Debug;
}
return r;
@@ -311,8 +317,18 @@ static CompilerResults CompileCode (IEnumerable references, TemplateSett
}
#endif
- static string [] ProcessReferences (ITextTemplatingEngineHost host, ParsedTemplate pt, TemplateSettings settings)
+ protected static string[] ProcessReferences (ITextTemplatingEngineHost host, ParsedTemplate pt, TemplateSettings settings)
{
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+ if (pt == null) {
+ throw new ArgumentNullException (nameof (pt));
+ }
+ if (settings == null) {
+ throw new ArgumentNullException (nameof (settings));
+ }
+
var resolved = new Dictionary ();
foreach (string assem in settings.Assemblies.Union (host.StandardAssemblyReferences)) {
@@ -335,12 +351,21 @@ static string [] ProcessReferences (ITextTemplatingEngineHost host, ParsedTempla
public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, ParsedTemplate pt)
{
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+ if (pt == null) {
+ throw new ArgumentNullException (nameof (pt));
+ }
+
var settings = new TemplateSettings ();
- bool relativeLinePragmas = host.GetHostOption ("UseRelativeLinePragmas") as bool? ?? false;
+ bool relativeLinePragmas = host.GetHostOption (nameof (TemplateSettings.UseRelativeLinePragmas)) as bool? ?? false;
foreach (Directive dt in pt.Directives) {
+#pragma warning disable CA1308 // Normalize strings to uppercase
switch (dt.Name.ToLowerInvariant ()) {
+#pragma warning restore CA1308 // Normalize strings to uppercase
case "template":
string val = dt.Extract ("language");
if (val != null)
@@ -368,15 +393,15 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars
settings.HostSpecific = string.Compare (val, "true", StringComparison.OrdinalIgnoreCase) == 0;
}
}
- val = dt.Extract ("CompilerOptions");
+ val = dt.Extract (nameof (TemplateSettings.CompilerOptions)) ?? host.GetHostOption(nameof(TemplateSettings.CompilerOptions))?.ToString().ToLower();
if (val != null) {
settings.CompilerOptions = val;
}
- val = dt.Extract ("relativeLinePragmas");
+ val = dt.Extract ("relativeLinePragmas") ?? host.GetHostOption (nameof (TemplateSettings.UseRelativeLinePragmas))?.ToString().ToLower();
if (val != null) {
relativeLinePragmas = string.Compare (val, "true", StringComparison.OrdinalIgnoreCase) == 0;
}
- val = dt.Extract ("linePragmas");
+ val = dt.Extract ("linePragmas") ?? host.GetHostOption (nameof (TemplateSettings.NoLinePragmas))?.ToString ().ToLower ();
if (val != null) {
settings.NoLinePragmas = string.Compare (val, "false", StringComparison.OrdinalIgnoreCase) == 0;
}
@@ -440,7 +465,7 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars
//initialize the custom processors
foreach (var kv in settings.DirectiveProcessors) {
- kv.Value.Initialize (host);
+ kv.Value.Initialize (host, settings);
IRecognizeHostSpecific hs;
if (settings.HostSpecific || (
@@ -462,7 +487,7 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars
if (settings.Name == null)
settings.Name = "GeneratedTextTransformation";
if (settings.Namespace == null)
- settings.Namespace = string.Format (typeof (TextTransformation).Namespace + "{0:x}", new Random ().Next ());
+ settings.Namespace = string.Format (CultureInfo.InvariantCulture, typeof (TextTransformation).Namespace + "{0:x}", new Random ().Next ());
//resolve the CodeDOM provider
if (String.IsNullOrEmpty (settings.Language)) {
@@ -483,7 +508,30 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars
return settings;
}
- settings.RelativeLinePragmas = relativeLinePragmas;
+ settings.UseRelativeLinePragmas = relativeLinePragmas;
+
+ if (host.GetHostOption (nameof (TemplateSettings.CachedTemplates)) is bool cachedTemplates) {
+ settings.CachedTemplates = cachedTemplates;
+ }
+
+ if (host.GetHostOption (nameof (TemplateSettings.Log)) is TextWriter output) {
+ settings.Log = output;
+ }
+
+#if !NET35
+ if (host.GetHostOption (nameof (TemplateSettings.CancellationToken)) is CancellationToken cancellationToken) {
+ settings.CancellationToken = cancellationToken;
+ }
+ else {
+ settings.CancellationToken = CancellationToken.None;
+ }
+
+ if ((host.GetHostOption (nameof (TemplateSettings.RuntimeKind)) ?? RuntimeKind.Default) is RuntimeKind runtimeKind) {
+ settings.RuntimeKind = runtimeKind;
+ }
+#endif
+
+
return settings;
}
@@ -497,6 +545,10 @@ public static string IndentSnippetText (CodeDomProvider provider, string text, s
public static string IndentSnippetText (string text, string indent)
{
+ if (text == null) {
+ throw new ArgumentNullException (nameof (text));
+ }
+
var builder = new StringBuilder (text.Length);
builder.Append (indent);
int lastNewline = 0;
@@ -528,21 +580,27 @@ public static string IndentSnippetText (string text, string indent)
static void AddDirective (TemplateSettings settings, ITextTemplatingEngineHost host, string processorName, Directive directive)
{
- if (!settings.DirectiveProcessors.TryGetValue (processorName, out IDirectiveProcessor processor)) {
- switch (processorName) {
- case "ParameterDirectiveProcessor":
- processor = new ParameterDirectiveProcessor ();
- break;
- default:
- Type processorType = host.ResolveDirectiveProcessor (processorName);
- processor = (IDirectiveProcessor)Activator.CreateInstance (processorType);
- break;
- }
- if (!processor.IsDirectiveSupported (directive.Name))
- throw new InvalidOperationException ("Directive processor '" + processorName + "' does not support directive '" + directive.Name + "'");
+ if (settings.DirectiveProcessors.ContainsKey(processorName)) {
+ return;
+ }
- settings.DirectiveProcessors [processorName] = processor;
+ IDirectiveProcessor processor;
+
+ switch (processorName) {
+ case "ParameterDirectiveProcessor":
+ processor = new ParameterDirectiveProcessor ();
+ break;
+ default:
+ Type processorType = host.ResolveDirectiveProcessor (processorName);
+ processor = (IDirectiveProcessor)Activator.CreateInstance (processorType);
+ break;
}
+
+ if (!processor.IsDirectiveSupported (directive.Name))
+ throw new InvalidOperationException ("Directive processor '" + processorName + "' does not support directive '" + directive.Name + "'");
+
+ settings.DirectiveProcessors[processorName] = processor;
+
settings.CustomDirectives.Add (new CustomDirective (processorName, directive));
}
@@ -592,6 +650,18 @@ static void ProcessDirectives (string content, ParsedTemplate pt, TemplateSettin
public static CodeCompileUnit GenerateCompileUnit (ITextTemplatingEngineHost host, string content, ParsedTemplate pt, TemplateSettings settings)
{
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+
+ if (pt == null) {
+ throw new ArgumentNullException (nameof (pt));
+ }
+
+ if (settings == null) {
+ throw new ArgumentNullException (nameof (settings));
+ }
+
ProcessDirectives (content, pt, settings);
string baseDirectory = Path.GetDirectoryName (host.TemplateFile);
@@ -615,6 +685,8 @@ public static CodeCompileUnit GenerateCompileUnit (ITextTemplatingEngineHost hos
type.BaseTypes.Add (new CodeTypeReference (settings.Inherits));
} else if (!settings.IncludePreprocessingHelpers) {
type.BaseTypes.Add (TypeRef ());
+ // issue #87 because CompilerErrorCollection is referenced by the TextTransformation base class
+ TextTransformation.AddRequiredReferences (host.StandardAssemblyReferences);
} else {
type.BaseTypes.Add (new CodeTypeReference (settings.Name + "Base"));
}
@@ -623,7 +695,7 @@ public static CodeCompileUnit GenerateCompileUnit (ITextTemplatingEngineHost hos
//prep the transform method
var transformMeth = new CodeMemberMethod {
Name = "TransformText",
- ReturnType = new CodeTypeReference (typeof (String)),
+ ReturnType = new CodeTypeReference (typeof (string)),
Attributes = MemberAttributes.Public,
};
if (!settings.IncludePreprocessingHelpers)
@@ -652,7 +724,7 @@ public static CodeCompileUnit GenerateCompileUnit (ITextTemplatingEngineHost hos
CodeLinePragma location = null;
if (!settings.NoLinePragmas) {
var f = seg.StartLocation.FileName ?? host.TemplateFile;
- if (settings.RelativeLinePragmas)
+ if (settings.UseRelativeLinePragmas)
f = FileUtil.AbsoluteToRelativePath (baseDirectory, f).Replace ('\\', '/');
location = new CodeLinePragma (f, seg.StartLocation.Line);
}
@@ -838,6 +910,10 @@ static void GenerateInitializationMethod (CodeTypeDeclaration type, TemplateSett
static void GenerateProcessingHelpers (CodeTypeDeclaration type, TemplateSettings settings)
{
+ if (settings == null) {
+ throw new ArgumentNullException (nameof (settings));
+ }
+
var thisRef = new CodeThisReferenceExpression ();
var sbTypeRef = TypeRef ();
@@ -1231,9 +1307,18 @@ static CodeMemberField PrivateField (CodeTypeReference typeRef, string name)
///
public static void GenerateCodeFromMembers (CodeDomProvider provider, CodeGeneratorOptions options, StringWriter sw, IEnumerable members)
{
+ if (provider == null) {
+ throw new ArgumentNullException (nameof (provider));
+ }
+
+ if (members == null) {
+ throw new ArgumentNullException (nameof (members));
+ }
+
if (!useMonoHack) {
- foreach (CodeTypeMember member in members)
+ foreach (CodeTypeMember member in members) {
provider.GenerateCodeFromMember (member, sw, options);
+ }
return;
}
diff --git a/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/ProcessTemplateEventArgs.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/ProcessTemplateEventArgs.cs
new file mode 100644
index 0000000..0406257
--- /dev/null
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/ProcessTemplateEventArgs.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.VisualStudio.TextTemplating.VSHost
+{
+ public class ProcessTemplateEventArgs : EventArgs
+ {
+ public string TemplateOutput { get; set; }
+ public bool Succeeded { get; set; }
+ }
+}
diff --git a/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TextTemplatingCallback.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TextTemplatingCallback.cs
new file mode 100644
index 0000000..2a69a91
--- /dev/null
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TextTemplatingCallback.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Text;
+
+namespace Mono.VisualStudio.TextTemplating.VSHost
+{
+ public class TextTemplatingCallback
+ : ITextTemplatingCallback
+ {
+ bool isFromOutputDirective;
+
+ public bool Errors { get; set; }
+
+ public string Extension { get; private set; } = null;
+
+ public Encoding OutputEncoding { get; private set; } = Encoding.UTF8;
+
+ public void Initialize()
+ {
+ Errors = false;
+ Extension = null;
+ OutputEncoding = Encoding.UTF8;
+ isFromOutputDirective = false;
+ }
+
+ public void ErrorCallback (bool warning, string message, int line, int column)
+ {
+ Errors = true;
+ }
+
+ public void SetFileExtension (string extension)
+ {
+ Extension = extension ?? throw new ArgumentNullException (nameof (extension));
+ }
+
+ public void SetOutputEncoding (Encoding encoding, bool fromOutputDirective)
+ {
+ if (!isFromOutputDirective) {
+ if (fromOutputDirective) {
+ isFromOutputDirective = true;
+ OutputEncoding = encoding ?? throw new ArgumentNullException (nameof (encoding));
+ } else {
+ if ((OutputEncoding != null) && !ReferenceEquals (encoding, OutputEncoding)) {
+ OutputEncoding = Encoding.UTF8;
+ }
+ OutputEncoding = encoding;
+ }
+ }
+ }
+
+ public ITextTemplatingCallback DeepCopy ()
+ {
+ TextTemplatingCallback callback = (TextTemplatingCallback)base.MemberwiseClone ();
+
+ if (Extension != null) {
+ callback.Extension = (string)Extension.Clone ();
+ }
+ if (OutputEncoding != null) {
+ callback.OutputEncoding = (Encoding)OutputEncoding.Clone ();
+ }
+
+ return callback;
+ }
+ }
+}
diff --git a/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TransformationRunFactory.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TransformationRunFactory.cs
new file mode 100644
index 0000000..f8d8106
--- /dev/null
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TransformationRunFactory.cs
@@ -0,0 +1,32 @@
+using System;
+using Mono.TextTemplating;
+
+namespace Mono.VisualStudio.TextTemplating.VSHost
+{
+ public abstract class TransformationRunFactory
+ : MarshalByRefObject
+ , IProcessTransformationRunFactory
+ {
+ public const string TransformationRunFactoryPrefix = "TransformationRunFactoryService";
+ public const string TransformationRunFactorySuffix = nameof (TransformationRunFactory);
+ ///
+ /// Create the transformation runner
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// abstracted, just because I am uncertain on how this would run on multiple platforms. Also visual studio classes may be required to pull of correctly.
+ ///
+ public abstract IProcessTransformationRun CreateTransformationRun (Type runnerType, ParsedTemplate pt, ResolveEventHandler resolver);
+
+ public abstract string RunTransformation (IProcessTransformationRun transformationRun);
+
+ public override object InitializeLifetimeService ()
+ {
+ return null;
+ }
+
+ }
+}
diff --git a/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TransformationRunner.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TransformationRunner.cs
new file mode 100644
index 0000000..b27fa82
--- /dev/null
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating.VSHost/TransformationRunner.cs
@@ -0,0 +1,244 @@
+using System;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using Mono.TextTemplating;
+
+namespace Mono.VisualStudio.TextTemplating.VSHost
+{
+ public class TransformationRunner
+ : MarshalByRefObject
+ , IProcessTransformationRun
+ {
+ CompiledTemplate compiledTemplate;
+ TemplateSettings settings;
+ ITextTemplatingEngineHost host;
+
+ public CompilerErrorCollection Errors { get; private set; }
+
+ public virtual string PerformTransformation ()
+ {
+ string errorOutput = VsTemplatingErrorResources.ErrorOutput;
+
+ if (compiledTemplate == null) {
+ LogError (VsTemplatingErrorResources.ErrorInitializingTransformationObject, false);
+
+ return errorOutput;
+ }
+
+ object transform = null;
+
+ try {
+ transform = CreateTextTransformation (settings, host, compiledTemplate.Assembly);
+
+ return compiledTemplate.Process (transform);
+ }
+ catch (Exception ex) {
+ if (TemplatingEngine.IsCriticalException(ex)) {
+ throw;
+ }
+ LogError (ex.ToString (), false);
+ }
+ finally {
+ if (transform is IDisposable disposable) {
+ disposable.Dispose ();
+ }
+ compiledTemplate?.Dispose ();
+ compiledTemplate = null;
+ host = null;
+ }
+
+ return errorOutput;
+ }
+
+ static PropertyInfo GetDerivedProperty (Type transformType, string propertyName)
+ {
+ while(transformType != typeof(object) && transformType != null) {
+ PropertyInfo property = transformType.GetProperty (propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
+ if (property != null) {
+ return property;
+ }
+ transformType = transformType.BaseType;
+ }
+ return null;
+ }
+
+ protected virtual object CreateTextTransformation(TemplateSettings settings, ITextTemplatingEngineHost host, Assembly assembly) {
+ object success = null;
+
+ if (settings == null) {
+ throw new ArgumentNullException (nameof (settings));
+ }
+
+ if (host == null) {
+ throw new ArgumentNullException (nameof (host));
+ }
+
+ if (assembly == null) {
+ throw new ArgumentNullException (nameof (assembly));
+ }
+
+ try {
+ Type type;
+
+ var result = assembly.CreateInstance (settings.GetFullName ());
+
+ if (result != null) {
+ type = result.GetType ();
+
+ if (settings.HostPropertyOnBase || settings.HostSpecific) {
+ try {
+ PropertyInfo property = type.GetProperty ("Host");
+
+ if (property != null) {
+ property?.SetValue (result, host, null);
+ }
+ else {
+ LogError (string.Format(CultureInfo.CurrentCulture, VsTemplatingErrorResources.HostPropertyNotFound, settings.HostType.Name), false);
+ }
+ }
+ catch(Exception hostException) {
+ if (TemplatingEngine.IsCriticalException(hostException)) {
+ throw;
+ }
+ LogError (string.Format (CultureInfo.CurrentCulture, VsTemplatingErrorResources.ExceptionSettingHost, settings.GetFullName ()), false);
+ }
+ }
+
+ try {
+ if (host is ITextTemplatingSessionHost sessionHost &&
+ sessionHost.Session != null) {
+ PropertyInfo property = GetDerivedProperty (type, nameof (TextTransformation.Session));
+
+ property?.SetValue (result, sessionHost.Session, null);
+ }
+ else {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, VsTemplatingErrorResources.SessionHostSessionNotInitialized, settings.GetFullName()));
+ }
+ }
+ catch (Exception sessionException) {
+ if (TemplatingEngine.IsCriticalException (sessionException)) {
+ throw;
+ }
+ LogError (string.Format (CultureInfo.CurrentCulture, VsTemplatingErrorResources.ExceptionSettingSession, sessionException), false);
+ }
+ success = result;
+
+ } else {
+ LogError (VsTemplatingErrorResources.ExceptionInstantiatingTransformationObject, false);
+ }
+ }
+ catch(Exception instantiatingException) {
+ if (TemplatingEngine.IsCriticalException (instantiatingException)) {
+ throw;
+ }
+ LogError (VsTemplatingErrorResources.ExceptionInstantiatingTransformationObject + string.Format(CultureInfo.CurrentCulture, VsTemplatingErrorResources.Exception, instantiatingException), false);
+ success = null;
+ }
+ return success;
+ }
+
+ public virtual bool PrepareTransformation (ParsedTemplate pt, string content, ITextTemplatingEngineHost host, TemplateSettings settings)
+ {
+ this.host = host ?? throw new ArgumentNullException (nameof (host));
+ this.settings = settings ?? throw new ArgumentNullException (nameof (settings));
+
+ try {
+ this.settings.Assemblies.Add (base.GetType ().Assembly.Location);
+ this.settings.Assemblies.Add (typeof (ITextTemplatingEngineHost).Assembly.Location);
+ this.compiledTemplate = LocateAssembly (pt, content);
+ }
+ catch(Exception ex) {
+ if (TemplatingEngine.IsCriticalException (ex)) {
+ throw;
+ }
+ LogError (string.Format (CultureInfo.CurrentCulture, VsTemplatingErrorResources.Exception, ex), false);
+ }
+ return this.compiledTemplate != null;
+ }
+
+ CompiledTemplate LocateAssembly (ParsedTemplate pt, string content)
+ {
+ CompiledTemplate compiledTemplate = null;
+
+ if (settings.CachedTemplates) {
+ compiledTemplate = CompiledTemplateCache.Find (settings.GetFullName ());
+ }
+ if (compiledTemplate == null) {
+ compiledTemplate = Compile (pt, content);
+ if (settings.CachedTemplates && compiledTemplate != null) {
+ CompiledTemplateCache.Insert (settings.GetFullName (), compiledTemplate);
+ }
+ }
+ return compiledTemplate;
+ }
+
+ CompiledTemplate Compile (ParsedTemplate pt, string content)
+ {
+ CompiledTemplate compiledTemplate = null;
+
+ if (host is ITextTemplatingComponents Component &&
+ Component.Engine is IProcessTextTemplatingEngine engine) {
+ compiledTemplate = engine.CompileTemplate (pt, content, host, settings);
+
+ if (settings.CachedTemplates) {
+ // we will resolve loading of assemblies through the run factory for cached templates
+ compiledTemplate?.Dispose ();
+ }
+ }
+
+ return compiledTemplate;
+ }
+
+ //public virtual void PreLoadAssemblies (IEnumerable assemblies)
+ //{
+ // try {
+ // //TODO:: investigate preloading assemblies with the AssemblyLoadContext
+ // }catch(Exception ex) {
+ // if (TemplatingEngine.IsCriticalException (ex)) {
+ // throw;
+ // }
+ // }
+ //}
+
+ protected Assembly AttemptAssemblyLoad(AssemblyName assembly)
+ {
+ try {
+ return Assembly.LoadFrom (assembly.CodeBase);
+ }
+ catch(Exception ex) {
+ LogError (string.Format (CultureInfo.CurrentCulture, VsTemplatingErrorResources.AssemblyLoadError, assembly.Name, ex), false);
+ return null;
+ }
+ }
+
+ public void ClearErrors()
+ {
+ Errors.Clear ();
+ }
+
+ protected void LogError(string message, bool isWarning)
+ {
+ CompilerError error = new CompilerError () {
+ ErrorText = message,
+ IsWarning = isWarning
+ };
+
+ Errors.Add (error);
+ }
+
+ protected void LogError(string message, bool isWarning, string filename, int line, int column)
+ {
+ CompilerError error = new CompilerError () {
+ ErrorText = message,
+ IsWarning = isWarning,
+ FileName = filename,
+ Line = line,
+ Column = column
+ };
+
+ Errors.Add (error);
+ }
+ }
+}
diff --git a/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/CompiledTemplateCache.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/CompiledTemplateCache.cs
new file mode 100644
index 0000000..ad97284
--- /dev/null
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/CompiledTemplateCache.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using Mono.TextTemplating;
+
+namespace Mono.VisualStudio.TextTemplating
+{
+ public static class CompiledTemplateCache
+ {
+ public static Dictionary compiledTemplates = new Dictionary (0x23);
+ public static DateTime lastUse;
+
+ public static CompiledTemplate Find(string fullClassName)
+ {
+ CompiledTemplate compiledTemplate = null;
+ Dictionary compiledTemplates = CompiledTemplateCache.compiledTemplates;
+ lock (compiledTemplates) {
+ lastUse = DateTime.Now;
+ if (CompiledTemplateCache.compiledTemplates.TryGetValue(fullClassName, out CompiledTemplateRecord record)) {
+ compiledTemplate = record.CompiledTemplate;
+ record.LastUse = lastUse;
+ }
+ }
+ return compiledTemplate;
+ }
+
+ public static void Insert (string classFullName, CompiledTemplate compiledTemplate)
+ {
+ Dictionary assemblies = CompiledTemplateCache.compiledTemplates;
+ lock (assemblies) {
+ CompiledTemplateCache.compiledTemplates[classFullName] = new CompiledTemplateRecord (compiledTemplate);
+ lastUse = DateTime.Now;
+ }
+ }
+ }
+}
diff --git a/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/CompiledTemplateRecord.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/CompiledTemplateRecord.cs
new file mode 100644
index 0000000..e117012
--- /dev/null
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/CompiledTemplateRecord.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Reflection;
+using Mono.TextTemplating;
+
+namespace Mono.VisualStudio.TextTemplating
+{
+ public class CompiledTemplateRecord
+ {
+ readonly CompiledTemplate compiledTemplate;
+
+ public CompiledTemplate CompiledTemplate => compiledTemplate;
+ public DateTime LastUse { get; set; }
+
+ public CompiledTemplateRecord(CompiledTemplate compiledTemplate)
+ {
+ this.compiledTemplate = compiledTemplate;
+ LastUse = DateTime.Now;
+ }
+ }
+}
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessor.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/DirectiveProcessor.cs
similarity index 84%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessor.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/DirectiveProcessor.cs
index aae9e09..93e5950 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessor.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/DirectiveProcessor.cs
@@ -28,27 +28,33 @@
using System.Collections.Generic;
using System.CodeDom.Compiler;
using System.CodeDom;
+using Mono.TextTemplating;
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
public abstract class DirectiveProcessor : IDirectiveProcessor
{
+ protected ITextTemplatingEngineHost Host { get; private set; }
+ protected TemplateSettings Settings { get; private set; }
+
CompilerErrorCollection errors;
protected DirectiveProcessor ()
{
}
- public virtual void Initialize (ITextTemplatingEngineHost host)
+ public virtual void Initialize (ITextTemplatingEngineHost host, TemplateSettings settings)
{
- if (host == null)
- throw new ArgumentNullException ("host");
+ this.Host = host ?? throw new ArgumentNullException (nameof (host));
+ this.Settings = settings ?? throw new ArgumentNullException (nameof (settings));
}
public virtual void StartProcessingRun (CodeDomProvider languageProvider, string templateContents, CompilerErrorCollection errors)
{
- if (languageProvider == null)
- throw new ArgumentNullException ("languageProvider");
+ if (languageProvider == null) {
+ throw new ArgumentNullException (nameof (languageProvider));
+ }
+
this.errors = errors;
}
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessorException.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/DirectiveProcessorException.cs
similarity index 97%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessorException.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/DirectiveProcessorException.cs
index ffc08cd..90cdd84 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessorException.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/DirectiveProcessorException.cs
@@ -27,7 +27,7 @@
using System;
using System.Runtime.Serialization;
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
[Serializable]
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/EncodingHelper.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/EncodingHelper.cs
similarity index 63%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/EncodingHelper.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/EncodingHelper.cs
index 89a6a46..8d771e7 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/EncodingHelper.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/EncodingHelper.cs
@@ -26,15 +26,27 @@
using System;
using System.Text;
+using System.IO;
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
- [Obsolete("Not implemented")]
public static class EncodingHelper
{
public static Encoding GetEncoding (string filePath)
{
- throw new NotImplementedException ();
+ var bom = new byte[4];
+ using (FileStream stream = File.OpenRead (filePath)) {
+ stream.Read (bom, 0, bom.Length);
+ }
+
+ if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) { return Encoding.UTF7; }
+ if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) { return Encoding.UTF8; }
+ if (bom[0] == 0xff && bom[1] == 0xfe && bom[2] == 0 && bom[3] == 0) { return Encoding.UTF32; } //UTF-32LE
+ if (bom[0] == 0xff && bom[1] == 0xfe) { return Encoding.Unicode; } //UTF-16LE
+ if (bom[0] == 0xfe && bom[1] == 0xff) { return Encoding.BigEndianUnicode; } //UTF-16BE
+ if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) { return new UTF32Encoding (true, true); } //UTF-32BE
+
+ return null;
}
}
}
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Interfaces.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/Interfaces.cs
similarity index 57%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Interfaces.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/Interfaces.cs
index d2eb60e..1104b6a 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/Interfaces.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/Interfaces.cs
@@ -29,18 +29,75 @@
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
+#if NET45 || NETSTANDARD
+using System.Threading.Tasks;
+#endif
using System.Runtime.Serialization;
using System.Text;
+using Mono.TextTemplating;
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
+ using Mono.VisualStudio.TextTemplating.VSHost;
+
public interface IRecognizeHostSpecific
{
void SetProcessingRunIsHostSpecific (bool hostSpecific);
bool RequiresProcessingRunIsHostSpecific { get; }
}
- [Obsolete("Use Mono.TextTemplating.TemplatingEngine directly")]
+ public interface ITextTemplatingService
+ : ITextTemplatingEngineHost
+ , ITextTemplatingSessionHost
+ , ITextTemplatingComponents
+ , IProcessTextTemplating
+ , ITextTemplating
+ {
+ new IProcessTextTemplatingEngine Engine { get; }
+ }
+
+ public interface IProcessTextTemplating
+ : ITextTemplating
+ {
+ event EventHandler TransformProcessCompleted;
+#if NETSTANDARD || NET45
+ Task ProcessTemplateAsync (string inputFilename, string content, ITextTemplatingCallback callback, object hierarchy, bool debugging = false);
+#elif NET35
+ void ProcessTemplate (string inputFilename, string content, ITextTemplatingCallback callback, object hierarchy, bool debugging = false);
+#endif
+ }
+
+ public interface ITextTemplating
+ {
+ void BeginErrorSession ();
+ bool EndErrorSession ();
+ string PreprocessTemplate (string inputFile, string content, ITextTemplatingCallback callback, string className, string classNamespace, out string[] references);
+ string ProcessTemplate (string inputFile, string content, ITextTemplatingCallback callback = null, object hierarchy = null);
+ }
+
+ public interface IProcessTransformationRun
+ {
+ string PerformTransformation ();
+
+ CompilerErrorCollection Errors { get; }
+ }
+
+ public interface IProcessTransformationRunFactory
+ {
+ IProcessTransformationRun CreateTransformationRun (Type runnerType, ParsedTemplate pt, ResolveEventHandler resolver);
+
+ string RunTransformation (IProcessTransformationRun transformationRun);
+ }
+
+ public interface IProcessTextTemplatingEngine
+ : ITextTemplatingEngine
+ {
+ IProcessTransformationRun PrepareTransformationRun (string content, ITextTemplatingEngineHost host, IProcessTransformationRunFactory runFactory, bool debugging = false);
+
+ CompiledTemplate CompileTemplate (string content, ITextTemplatingEngineHost host);
+ CompiledTemplate CompileTemplate (ParsedTemplate pt, string content, ITextTemplatingEngineHost host, TemplateSettings settings = null);
+ }
+
public interface ITextTemplatingEngine
{
string ProcessTemplate (string content, ITextTemplatingEngineHost host);
@@ -48,6 +105,31 @@ string PreprocessTemplate (string content, ITextTemplatingEngineHost host, strin
string classNamespace, out string language, out string [] references);
}
+ public interface ITextTemplatingComponents
+ {
+ ITextTemplatingEngineHost Host { get; }
+
+ ITextTemplatingEngine Engine { get; }
+
+ string TemplateFile { get; set; }
+
+ ITextTemplatingCallback Callback { get; set; }
+
+ object Hierarchy { get; set; }
+ }
+
+ public interface ITextTemplatingCallback
+ {
+ bool Errors { get; set; }
+ string Extension { get; }
+ void ErrorCallback (bool warning, string message, int line, int column);
+ void SetFileExtension (string extension);
+ void SetOutputEncoding (Encoding encoding, bool fromOutputDirective);
+ ITextTemplatingCallback DeepCopy ();
+
+ Encoding OutputEncoding { get; }
+ }
+
public interface ITextTemplatingEngineHost
{
object GetHostOption (string optionName);
@@ -77,7 +159,8 @@ public interface ITextTemplatingSession :
Guid Id { get; }
}
- public interface ITextTemplatingSessionHost
+ public interface ITextTemplatingSessionHost
+ : ISerializable
{
ITextTemplatingSession CreateSession ();
ITextTemplatingSession Session { get; set; }
@@ -95,7 +178,7 @@ public interface IDirectiveProcessor
string GetPreInitializationCodeForProcessingRun ();
string[] GetReferencesForProcessingRun ();
CodeAttributeDeclarationCollection GetTemplateClassCustomAttributes (); //TODO
- void Initialize (ITextTemplatingEngineHost host);
+ void Initialize (ITextTemplatingEngineHost host, TemplateSettings settings);
bool IsDirectiveSupported (string directiveName);
void ProcessDirective (string directiveName, IDictionary arguments);
void SetProcessingRunIsHostSpecific (bool hostSpecific);
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs
similarity index 89%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs
index 9810385..ee1a3b2 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs
@@ -29,8 +29,11 @@
using System.Collections.Generic;
using System.IO;
using Mono.TextTemplating;
+#if NET45
+using Mono.TextTemplating.CodeCompilation;
+#endif
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
public sealed class ParameterDirectiveProcessor : DirectiveProcessor, IRecognizeHostSpecific
{
@@ -143,23 +146,29 @@ public override void ProcessDirective (string directiveName, IDictionary providesDictionary);
@@ -120,9 +120,9 @@ void AssertNotProcessing ()
if (isInProcessingRun)
throw new InvalidOperationException ();
}
-
+
//FIXME: handle escaping
- IEnumerable> ParseArgs (string args)
+ static IEnumerable> ParseArgs (string args)
{
var pairs = args.Split (';');
foreach (var p in pairs) {
@@ -135,11 +135,12 @@ IEnumerable> ParseArgs (string args)
public override void ProcessDirective (string directiveName, IDictionary arguments)
{
- if (directiveName == null)
- throw new ArgumentNullException ("directiveName");
- if (arguments == null)
- throw new ArgumentNullException ("arguments");
-
+ if (directiveName == null) {
+ throw new ArgumentNullException (nameof (directiveName));
+ }
+ if (arguments == null) {
+ throw new ArgumentNullException (nameof (arguments));
+ }
var providesDictionary = new Dictionary ();
var requiresDictionary = new Dictionary ();
@@ -163,7 +164,7 @@ public override void ProcessDirective (string directiveName, IDictionary, ITextTemplatingSession, ISerializable
@@ -40,7 +40,6 @@ public TextTemplatingSession () : this (Guid.NewGuid ())
TextTemplatingSession (SerializationInfo info, StreamingContext context)
: base (info, context)
{
- Id = (Guid)info.GetValue ("Id", typeof (Guid));
}
public TextTemplatingSession (Guid id)
@@ -49,9 +48,10 @@ public TextTemplatingSession (Guid id)
}
public Guid Id {
- get; private set;
+ get => (Guid)this[nameof (Id)];
+ set => this[nameof (Id)] = value;
}
-
+
public override int GetHashCode ()
{
return Id.GetHashCode ();
@@ -76,7 +76,6 @@ public bool Equals (ITextTemplatingSession other)
void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
{
base.GetObjectData (info, context);
- info.AddValue ("Id", Id);
}
}
}
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTransformation.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/TextTransformation.cs
similarity index 84%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTransformation.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/TextTransformation.cs
index 119a98a..322c9c2 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTransformation.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/TextTransformation.cs
@@ -27,9 +27,11 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
using System.Text;
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
public abstract class TextTransformation : IDisposable
{
@@ -48,11 +50,13 @@ public virtual void Initialize ()
}
public abstract string TransformText ();
-
+
+#pragma warning disable CA2227 // Collection properties should be read only
public virtual IDictionary Session { get; set; }
-
+#pragma warning restore CA2227 // Collection properties should be read only
+
#region Errors
-
+
public void Error (string message)
{
Errors.Add (new CompilerError ("", 0, 0, "", message));
@@ -85,8 +89,9 @@ Stack Indents {
public string PopIndent ()
{
- if (Indents.Count == 0)
+ if (Indents.Count == 0) {
return "";
+ }
int lastPos = currentIndent.Length - Indents.Pop ();
string last = currentIndent.Substring (lastPos);
currentIndent = currentIndent.Substring (0, lastPos);
@@ -95,8 +100,9 @@ public string PopIndent ()
public void PushIndent (string indent)
{
- if (indent == null)
- throw new ArgumentNullException ("indent");
+ if (indent == null) {
+ throw new ArgumentNullException (nameof (indent));
+ }
Indents.Push (indent.Length);
currentIndent += indent;
}
@@ -176,7 +182,7 @@ public void Write (string textToAppend)
public void Write (string format, params object[] args)
{
- Write (string.Format (format, args));
+ Write (string.Format (CultureInfo.InvariantCulture, format, args));
}
public void WriteLine (string textToAppend)
@@ -188,7 +194,7 @@ public void WriteLine (string textToAppend)
public void WriteLine (string format, params object[] args)
{
- WriteLine (string.Format (format, args));
+ WriteLine (string.Format (CultureInfo.InvariantCulture, format, args));
}
#endregion
@@ -209,7 +215,20 @@ protected virtual void Dispose (bool disposing)
{
Dispose (false);
}
-
+
+ internal static void AddRequiredReferences (IList standardAssemblies)
+ {
+ if (standardAssemblies == null) {
+ throw new ArgumentNullException (nameof (standardAssemblies));
+ }
+
+ string codeDom = typeof (CompilerErrorCollection).Assembly.Location;
+
+ if (!standardAssemblies.Any (x => x.Equals (codeDom, StringComparison.CurrentCultureIgnoreCase))) {
+ standardAssemblies.Add (codeDom);
+ }
+ }
+
#endregion
}
diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ToStringHelper.cs b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/ToStringHelper.cs
similarity index 98%
rename from Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ToStringHelper.cs
rename to Mono.TextTemplating/Mono.VisualStudio.TextTemplating/ToStringHelper.cs
index ab9a0bf..2e4e832 100644
--- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ToStringHelper.cs
+++ b/Mono.TextTemplating/Mono.VisualStudio.TextTemplating/ToStringHelper.cs
@@ -27,7 +27,7 @@
using System;
using System.Reflection;
-namespace Microsoft.VisualStudio.TextTemplating
+namespace Mono.VisualStudio.TextTemplating
{
public static class ToStringHelper
{
diff --git a/Mono.TextTemplating/VsTemplatingErrorResources.Designer.cs b/Mono.TextTemplating/VsTemplatingErrorResources.Designer.cs
new file mode 100644
index 0000000..a9a5c0b
--- /dev/null
+++ b/Mono.TextTemplating/VsTemplatingErrorResources.Designer.cs
@@ -0,0 +1,162 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Mono.TextTemplating {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class VsTemplatingErrorResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal VsTemplatingErrorResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Mono.TextTemplating.VsTemplatingErrorResources", typeof(VsTemplatingErrorResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Assembly "{0}" Load Error: {1}.
+ ///
+ internal static string AssemblyLoadError {
+ get {
+ return ResourceManager.GetString("AssemblyLoadError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Error initializing the transformation object..
+ ///
+ internal static string ErrorInitializingTransformationObject {
+ get {
+ return ResourceManager.GetString("ErrorInitializingTransformationObject", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to // Error Generating Output.
+ ///
+ internal static string ErrorOutput {
+ get {
+ return ResourceManager.GetString("ErrorOutput", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exception: {0}.
+ ///
+ internal static string Exception {
+ get {
+ return ResourceManager.GetString("Exception", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Error Instanciating Object: .
+ ///
+ internal static string ExceptionInstantiatingTransformationObject {
+ get {
+ return ResourceManager.GetString("ExceptionInstantiatingTransformationObject", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exception Processing Template: {0}.
+ ///
+ internal static string ExceptionProcessingTemplate {
+ get {
+ return ResourceManager.GetString("ExceptionProcessingTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exception setting host property on: {0}.
+ ///
+ internal static string ExceptionSettingHost {
+ get {
+ return ResourceManager.GetString("ExceptionSettingHost", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exception setting session on: {0}.
+ ///
+ internal static string ExceptionSettingSession {
+ get {
+ return ResourceManager.GetString("ExceptionSettingSession", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Host Property Not Found On: {0}.
+ ///
+ internal static string HostPropertyNotFound {
+ get {
+ return ResourceManager.GetString("HostPropertyNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Something bad happened while prepping transformation..
+ ///
+ internal static string SessionHostMarshalError {
+ get {
+ return ResourceManager.GetString("SessionHostMarshalError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Session host session is not initialized for {0}..
+ ///
+ internal static string SessionHostSessionNotInitialized {
+ get {
+ return ResourceManager.GetString("SessionHostSessionNotInitialized", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Mono.TextTemplating/VsTemplatingErrorResources.resx b/Mono.TextTemplating/VsTemplatingErrorResources.resx
new file mode 100644
index 0000000..65f4ea5
--- /dev/null
+++ b/Mono.TextTemplating/VsTemplatingErrorResources.resx
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Assembly "{0}" Load Error: {1}
+
+
+ Error initializing the transformation object.
+
+
+ // Error Generating Output
+
+
+ Exception: {0}
+
+
+ Error Instanciating Object:
+
+
+ Exception Processing Template: {0}
+
+
+ Exception setting host property on: {0}
+
+
+ Exception setting session on: {0}
+
+
+ Host Property Not Found On: {0}
+
+
+ Something bad happened while prepping transformation.
+
+
+ Session host session is not initialized for {0}.
+
+
\ No newline at end of file
diff --git a/TextTransform/TextTransform.csproj b/TextTransform/TextTransform.csproj
index 71232d6..599c599 100644
--- a/TextTransform/TextTransform.csproj
+++ b/TextTransform/TextTransform.csproj
@@ -16,6 +16,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -24,4 +28,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/dotnet-t4-project-tool/dotnet-t4-project-tool.csproj b/dotnet-t4-project-tool/dotnet-t4-project-tool.csproj
index 10e2cff..2c7c9ee 100644
--- a/dotnet-t4-project-tool/dotnet-t4-project-tool.csproj
+++ b/dotnet-t4-project-tool/dotnet-t4-project-tool.csproj
@@ -22,6 +22,10 @@ This package can be installed into a project using `DotNetCliToolReference`.
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -31,4 +35,5 @@ This package can be installed into a project using `DotNetCliToolReference`.
+
diff --git a/dotnet-t4/TextTransform.cs b/dotnet-t4/TextTransform.cs
index 55e2ca7..89a9dab 100644
--- a/dotnet-t4/TextTransform.cs
+++ b/dotnet-t4/TextTransform.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
// Copyright (c) Microsoft Corp. (https://www.microsoft.com)
//
@@ -27,7 +27,7 @@
using System.Linq;
using System.Reflection;
using System.Text;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
using Mono.Options;
namespace Mono.TextTemplating
diff --git a/dotnet-t4/ToolTemplateGenerator.cs b/dotnet-t4/ToolTemplateGenerator.cs
index b077e2d..548466f 100644
--- a/dotnet-t4/ToolTemplateGenerator.cs
+++ b/dotnet-t4/ToolTemplateGenerator.cs
@@ -21,7 +21,7 @@
using System.CodeDom.Compiler;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
namespace Mono.TextTemplating
{
@@ -32,7 +32,7 @@ public ToolTemplateGenerator ()
Refs.Add (typeof (CompilerErrorCollection).Assembly.Location);
}
- protected override ITextTemplatingSession CreateSession () => new ToolTemplateSession (this);
+ protected override ITextTemplatingSession CreateSession () => new TextTemplatingSession (this);
public string PreprocessTemplate (
ParsedTemplate pt,
diff --git a/dotnet-t4/ToolTemplateSession.cs b/dotnet-t4/ToolTemplateSession.cs
index 8f00a03..592c51e 100644
--- a/dotnet-t4/ToolTemplateSession.cs
+++ b/dotnet-t4/ToolTemplateSession.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright (c) Microsoft Corp (https://www.microsoft.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -20,19 +20,19 @@
// THE SOFTWARE.
using System;
-using Microsoft.VisualStudio.TextTemplating;
+using Mono.VisualStudio.TextTemplating;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Mono.TextTemplating
{
- class ToolTemplateSession : ITextTemplatingSession
+ class TextTemplatingSession : ITextTemplatingSession
{
readonly Dictionary session = new Dictionary ();
readonly ToolTemplateGenerator toolTemplateGenerator;
- public ToolTemplateSession (ToolTemplateGenerator toolTemplateGenerator)
+ public TextTemplatingSession (ToolTemplateGenerator toolTemplateGenerator)
{
this.toolTemplateGenerator = toolTemplateGenerator;
}
@@ -46,7 +46,7 @@ public object this [string key] {
public ICollection Keys => session.Keys;
public ICollection