Skip to content

Commit 10765a6

Browse files
committed
2 parents 9c1671d + 7f18b1c commit 10765a6

11 files changed

+141
-42
lines changed

Pack.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
dotnet build -c Release
22
dotnet test
33
dotnet pack -c Release -o artifacts RazorEngineCore\RazorEngineCore.csproj -p:symbolPackageFormat=snupkg --include-symbols
4-
dotnet nuget push artifacts\RazorEngineCore.2022.8.1.nupkg --source https://www.nuget.org/api/v2/package -k KEY
4+
dotnet nuget push artifacts\RazorEngineCore.2022.8.1.nupkg --source https://www.nuget.org/api/v2/package -k KEY

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* .NET Framework 4.7.2
77
* Windows / Linux
88
* Publish as single file supported
9+
* Thread safe
910

1011
[![NuGet](https://img.shields.io/nuget/dt/RazorEngineCore.svg?style=flat-square)](https://www.nuget.org/packages/RazorEngineCore)
1112
[![NuGet](https://img.shields.io/nuget/v/RazorEngineCore.svg?style=flat-square)](https://www.nuget.org/packages/RazorEngineCore)
@@ -168,7 +169,7 @@ output:
168169
string content = @"Hello @A, @B, @Decorator(123)";
169170

170171
IRazorEngine razorEngine = new RazorEngine();
171-
IRazorEngineCompiledTemplate<CustomModel> template = razorEngine.Compile<CustomModel>(content);
172+
IRazorEngineCompiledTemplate<CustomTemplate> template = razorEngine.Compile<CustomTemplate>(content);
172173

173174
string result = template.Run(instance =>
174175
{
@@ -179,7 +180,7 @@ string result = template.Run(instance =>
179180
Console.WriteLine(result);
180181
```
181182
```cs
182-
public class CustomModel : RazorEngineTemplateBase
183+
public class CustomTemplate : RazorEngineTemplateBase
183184
{
184185
public int A { get; set; }
185186
public string B { get; set; }
@@ -207,12 +208,31 @@ IRazorEngineCompiledTemplate compiledTemplate = razorEngine.Compile(templateText
207208
string result = compiledTemplate.Run(new { name = "Hello" });
208209
```
209210

211+
#### Debugging templates
212+
In the builder options, set GeneratePdbStream to true, and set the TemplateFilename.
213+
```cs
214+
razorEngine.Compile(templateSource, builder =>
215+
{
216+
builder.Options.GeneratePdbStream = true;
217+
builder.Options.TemplateFilename = "TemplateFilename.cshtml"
218+
});
219+
```
220+
Your debugger will popup a window asking you to find the source file, after which you can step through as normal.
221+
222+
To set a breakpoint add this line in a code block in the template.
223+
```cs
224+
System.Diagnostics.Debugger.Break();
225+
```
210226

211227
#### Credits
212228
This package is inspired by [Simon Mourier SO post](https://stackoverflow.com/a/47756437/267736)
213229

214230

215231
#### Changelog
232+
* 2022.8.1
233+
* Proper namespace handling for nested types and types without namespace #113 (thanks [@Kirmiir](https://github.com/Kirmiir))
234+
* 2022.7.6
235+
* Added the option to genereate pdb alongside the assembly which allows debugging the templates.
216236
* 2022.1.2
217237
* #94 publish as single file fix
218238
* 2022.1.1

RazorEngineCore/IRazorEngine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ IRazorEngineCompiledTemplate<T> Compile<T>(string content, Action<IRazorEngineCo
1010

1111
Task<IRazorEngineCompiledTemplate<T>> CompileAsync<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null)
1212
where T : IRazorEngineTemplate;
13-
13+
1414
IRazorEngineCompiledTemplate Compile(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null);
15-
15+
1616
Task<IRazorEngineCompiledTemplate> CompileAsync(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null);
1717
}
1818
}

RazorEngineCore/IRazorEngineCompilationOptionsBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ public interface IRazorEngineCompilationOptionsBuilder
1414
void AddMetadataReference(MetadataReference reference);
1515
void AddUsing(string namespaceName);
1616
void Inherits(Type type);
17+
void GeneratePdbStream(bool flag);
1718
}
1819
}
Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
using System;
2-
using System.IO;
3-
using System.Threading.Tasks;
4-
5-
namespace RazorEngineCore
6-
{
7-
public interface IRazorEngineCompiledTemplate<out T> where T : IRazorEngineTemplate
8-
{
9-
void SaveToStream(Stream stream);
10-
Task SaveToStreamAsync(Stream stream);
11-
void SaveToFile(string fileName);
12-
Task SaveToFileAsync(string fileName);
13-
string Run(Action<T> initializer);
14-
Task<string> RunAsync(Action<T> initializer);
15-
}
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
5+
namespace RazorEngineCore
6+
{
7+
public interface IRazorEngineCompiledTemplate<out T> where T : IRazorEngineTemplate
8+
{
9+
void SaveToStream(Stream stream);
10+
Task SaveToStreamAsync(Stream stream);
11+
void SaveToFile(string fileName);
12+
Task SaveToFileAsync(string fileName);
13+
void SavePdbToFile(string filename);
14+
Task SavePdbToFileAsync(string fileName);
15+
string Run(Action<T> initializer);
16+
Task<string> RunAsync(Action<T> initializer);
17+
}
1618
}

RazorEngineCore/RazorEngine.cs

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@ public class RazorEngine : IRazorEngine
1717
public IRazorEngineCompiledTemplate<T> Compile<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null) where T : IRazorEngineTemplate
1818
{
1919
IRazorEngineCompilationOptionsBuilder compilationOptionsBuilder = new RazorEngineCompilationOptionsBuilder();
20-
2120
compilationOptionsBuilder.AddAssemblyReference(typeof(T).Assembly);
2221
compilationOptionsBuilder.Inherits(typeof(T));
2322

2423
builderAction?.Invoke(compilationOptionsBuilder);
25-
26-
MemoryStream memoryStream = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
27-
28-
return new RazorEngineCompiledTemplate<T>(memoryStream, compilationOptionsBuilder.Options.TemplateNamespace);
24+
if (compilationOptionsBuilder.Options.GeneratePdbStream)
25+
{
26+
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
27+
return new RazorEngineCompiledTemplate<T>(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace, streams.pdb);
28+
}
29+
else
30+
{
31+
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
32+
return new RazorEngineCompiledTemplate<T>(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace);
33+
}
2934
}
3035

3136
public Task<IRazorEngineCompiledTemplate<T>> CompileAsync<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null) where T : IRazorEngineTemplate
@@ -39,30 +44,45 @@ public IRazorEngineCompiledTemplate Compile(string content, Action<IRazorEngineC
3944
compilationOptionsBuilder.Inherits(typeof(RazorEngineTemplateBase));
4045

4146
builderAction?.Invoke(compilationOptionsBuilder);
47+
if (compilationOptionsBuilder.Options.GeneratePdbStream)
48+
{
49+
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
50+
return new RazorEngineCompiledTemplate(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace, streams.pdb);
51+
}
52+
else
53+
{
54+
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
55+
return new RazorEngineCompiledTemplate(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace);
56+
}
4257

43-
MemoryStream memoryStream = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
44-
45-
return new RazorEngineCompiledTemplate(memoryStream, compilationOptionsBuilder.Options.TemplateNamespace);
4658
}
4759

4860
public Task<IRazorEngineCompiledTemplate> CompileAsync(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null)
4961
{
5062
return Task.Factory.StartNew(() => this.Compile(content: content, builderAction: builderAction));
5163
}
5264

53-
protected virtual MemoryStream CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options)
65+
protected virtual CompiledStreams CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options, MemoryStream pdbStream = null)
5466
{
5567
templateSource = this.WriteDirectives(templateSource, options);
68+
string projectPath = @".";
69+
string fileName = string.IsNullOrWhiteSpace(options.TemplateFilename) ? Path.GetRandomFileName() + ".cshtml" : options.TemplateFilename;
70+
71+
if (options.GeneratePdbStream)
72+
{
73+
projectPath = Path.GetTempPath();
74+
Directory.CreateDirectory(projectPath);
75+
File.WriteAllText(Path.Combine(projectPath, fileName), templateSource);
76+
}
5677

5778
RazorProjectEngine engine = RazorProjectEngine.Create(
5879
RazorConfiguration.Default,
59-
RazorProjectFileSystem.Create(@"."),
80+
RazorProjectFileSystem.Create(projectPath),
6081
(builder) =>
6182
{
6283
builder.SetNamespace(options.TemplateNamespace);
6384
});
6485

65-
string fileName = string.IsNullOrWhiteSpace(options.TemplateFilename) ? Path.GetRandomFileName() : options.TemplateFilename;
6686

6787
RazorSourceDocument document = RazorSourceDocument.Create(templateSource, fileName);
6888

@@ -73,7 +93,6 @@ protected virtual MemoryStream CreateAndCompileToStream(string templateSource, R
7393
new List<TagHelperDescriptor>());
7494

7595
RazorCSharpDocument razorCSharpDocument = codeDocument.GetCSharpDocument();
76-
7796
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(razorCSharpDocument.GeneratedCode);
7897

7998
CSharpCompilation compilation = CSharpCompilation.Create(
@@ -102,10 +121,12 @@ protected virtual MemoryStream CreateAndCompileToStream(string templateSource, R
102121
.Concat(options.MetadataReferences)
103122
.ToList(),
104123
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
105-
106-
MemoryStream memoryStream = new MemoryStream();
107-
108-
EmitResult emitResult = compilation.Emit(memoryStream);
124+
CompiledStreams streams = new CompiledStreams();
125+
EmitResult emitResult;
126+
if (options.GeneratePdbStream)
127+
emitResult = compilation.Emit(streams.assembly, streams.pdb);
128+
else
129+
emitResult = compilation.Emit(streams.assembly);
109130

110131
if (!emitResult.Success)
111132
{
@@ -118,9 +139,10 @@ protected virtual MemoryStream CreateAndCompileToStream(string templateSource, R
118139
throw exception;
119140
}
120141

121-
memoryStream.Position = 0;
122-
123-
return memoryStream;
142+
streams.assembly.Position = 0;
143+
if(options.GeneratePdbStream)
144+
streams.pdb.Position = 0;
145+
return streams;
124146
}
125147

126148
protected virtual string WriteDirectives(string content, RazorEngineCompilationOptions options)
@@ -137,5 +159,16 @@ protected virtual string WriteDirectives(string content, RazorEngineCompilationO
137159

138160
return stringBuilder.ToString();
139161
}
162+
163+
protected class CompiledStreams
164+
{
165+
public CompiledStreams()
166+
{
167+
assembly = new MemoryStream();
168+
pdb = new MemoryStream();
169+
}
170+
public MemoryStream assembly {get;set;}
171+
public MemoryStream pdb {get;set;}
172+
}
140173
}
141-
}
174+
}

RazorEngineCore/RazorEngineCompilationOptions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public class RazorEngineCompilationOptions
1414
public string TemplateNamespace { get; set; } = "TemplateNamespace";
1515
public string TemplateFilename { get; set; } = "";
1616
public string Inherits { get; set; } = "RazorEngineCore.RazorEngineTemplateBase";
17-
17+
///Set to true to generate PDB symbols information along with the assembly for debugging support
18+
public bool GeneratePdbStream {get;set;} = false;
1819
public HashSet<string> DefaultUsings { get; set; } = new HashSet<string>()
1920
{
2021
"System.Linq",

RazorEngineCore/RazorEngineCompilationOptionsBuilder.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,10 @@ private string RenderDeclaringType(Type type)
9292

9393
return parent + "." + type.Name;
9494
}
95+
96+
public void GeneratePdbStream(bool flag)
97+
{
98+
this.Options.GeneratePdbStream = flag;
99+
}
95100
}
96-
}
101+
}

RazorEngineCore/RazorEngineCompiledTemplate.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templ
1717
Assembly assembly = Assembly.Load(assemblyByteCode.ToArray());
1818
this.templateType = assembly.GetType(templateNamespace + ".Template");
1919
}
20+
internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templateNamespace, MemoryStream pdbByteCode)
21+
{
22+
this.assemblyByteCode = assemblyByteCode;
23+
24+
Assembly assembly = Assembly.Load(assemblyByteCode.ToArray(), pdbByteCode.ToArray());
25+
this.templateType = assembly.GetType(templateNamespace + ".Template");
26+
}
2027

2128
public static IRazorEngineCompiledTemplate LoadFromFile(string fileName, string templateNamespace = "TemplateNamespace")
2229
{

RazorEngineCore/RazorEngineCompiledTemplateT.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace RazorEngineCore
88
public class RazorEngineCompiledTemplate<T> : IRazorEngineCompiledTemplate<T> where T : IRazorEngineTemplate
99
{
1010
private readonly MemoryStream assemblyByteCode;
11+
private readonly MemoryStream pdbByteCode;
1112
private readonly Type templateType;
1213

1314
internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templateNamespace)
@@ -16,6 +17,14 @@ internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templ
1617

1718
Assembly assembly = Assembly.Load(assemblyByteCode.ToArray());
1819
this.templateType = assembly.GetType($"{templateNamespace}.Template");
20+
}
21+
internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templateNamespace, MemoryStream pdbByteCode)
22+
{
23+
this.assemblyByteCode = assemblyByteCode;
24+
this.pdbByteCode = pdbByteCode;
25+
26+
Assembly assembly = Assembly.Load(assemblyByteCode.ToArray(), pdbByteCode.ToArray());
27+
this.templateType = assembly.GetType(templateNamespace + ".Template");
1928
}
2029

2130
public static IRazorEngineCompiledTemplate<T> LoadFromFile(string fileName, string templateNamespace = "TemplateNamespace")
@@ -84,6 +93,24 @@ public Task SaveToFileAsync(string fileName)
8493
}
8594
}
8695

96+
public void SavePdbToFile(string fileName)
97+
{
98+
this.SavePdbToFileAsync(fileName).GetAwaiter().GetResult();
99+
}
100+
public Task SavePdbToFileAsync(string fileName)
101+
{
102+
using (FileStream fileStream = new FileStream(
103+
path: fileName,
104+
mode: FileMode.OpenOrCreate,
105+
access: FileAccess.Write,
106+
share: FileShare.None,
107+
bufferSize: 4096,
108+
useAsync: true))
109+
{
110+
return pdbByteCode.CopyToAsync(fileStream);
111+
}
112+
}
113+
87114
public string Run(Action<T> initializer)
88115
{
89116
return this.RunAsync(initializer).GetAwaiter().GetResult();
@@ -98,5 +125,7 @@ public async Task<string> RunAsync(Action<T> initializer)
98125

99126
return await instance.ResultAsync();
100127
}
128+
129+
101130
}
102131
}

0 commit comments

Comments
 (0)