Skip to content

Commit

Permalink
Merge pull request #111 from TheAtomicOption/pr/83-rebased-and-generic
Browse files Browse the repository at this point in the history
Update for debug templates pull request
  • Loading branch information
adoconnection authored Nov 15, 2023
2 parents c6ff488 + 11420b9 commit 7f18b1c
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 40 deletions.
2 changes: 1 addition & 1 deletion Pack.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dotnet build -c Release
dotnet test
dotnet pack -c Release -o artifacts RazorEngineCore\RazorEngineCore.csproj -p:symbolPackageFormat=snupkg --include-symbols
dotnet nuget push artifacts\RazorEngineCore.2022.8.1.nupkg --source https://www.nuget.org/api/v2/package -k KEY
dotnet nuget push artifacts\RazorEngineCore.2022.8.1.nupkg --source https://www.nuget.org/api/v2/package -k KEY
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,21 @@ IRazorEngineCompiledTemplate compiledTemplate = razorEngine.Compile(templateText
string result = compiledTemplate.Run(new { name = "Hello" });
```

#### Debugging templates
In the builder options, set GeneratePdbStream to true, and set the TemplateFilename.
```cs
razorEngine.Compile(templateSource, builder =>
{
builder.Options.GeneratePdbStream = true;
builder.Options.TemplateFilename = "TemplateFilename.cshtml"
});
```
Your debugger will popup a window asking you to find the source file, after which you can step through as normal.

To set a breakpoint add this line in a code block in the template.
```cs
System.Diagnostics.Debugger.Break();
```

#### Credits
This package is inspired by [Simon Mourier SO post](https://stackoverflow.com/a/47756437/267736)
Expand All @@ -216,6 +231,8 @@ This package is inspired by [Simon Mourier SO post](https://stackoverflow.com/a/
#### Changelog
* 2022.8.1
* Proper namespace handling for nested types and types without namespace #113 (thanks [@Kirmiir](https://github.com/Kirmiir))
* 2022.7.6
* Added the option to genereate pdb alongside the assembly which allows debugging the templates.
* 2022.1.2
* #94 publish as single file fix
* 2022.1.1
Expand Down
4 changes: 2 additions & 2 deletions RazorEngineCore/IRazorEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ IRazorEngineCompiledTemplate<T> Compile<T>(string content, Action<IRazorEngineCo

Task<IRazorEngineCompiledTemplate<T>> CompileAsync<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null)
where T : IRazorEngineTemplate;

IRazorEngineCompiledTemplate Compile(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null);

Task<IRazorEngineCompiledTemplate> CompileAsync(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null);
}
}
1 change: 1 addition & 0 deletions RazorEngineCore/IRazorEngineCompilationOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ public interface IRazorEngineCompilationOptionsBuilder
void AddMetadataReference(MetadataReference reference);
void AddUsing(string namespaceName);
void Inherits(Type type);
void GeneratePdbStream(bool flag);
}
}
32 changes: 17 additions & 15 deletions RazorEngineCore/IRazorEngineCompiledTemplateT.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using System;
using System.IO;
using System.Threading.Tasks;

namespace RazorEngineCore
{
public interface IRazorEngineCompiledTemplate<out T> where T : IRazorEngineTemplate
{
void SaveToStream(Stream stream);
Task SaveToStreamAsync(Stream stream);
void SaveToFile(string fileName);
Task SaveToFileAsync(string fileName);
string Run(Action<T> initializer);
Task<string> RunAsync(Action<T> initializer);
}
using System;
using System.IO;
using System.Threading.Tasks;

namespace RazorEngineCore
{
public interface IRazorEngineCompiledTemplate<out T> where T : IRazorEngineTemplate
{
void SaveToStream(Stream stream);
Task SaveToStreamAsync(Stream stream);
void SaveToFile(string fileName);
Task SaveToFileAsync(string fileName);
void SavePdbToFile(string filename);
Task SavePdbToFileAsync(string fileName);
string Run(Action<T> initializer);
Task<string> RunAsync(Action<T> initializer);
}
}
73 changes: 53 additions & 20 deletions RazorEngineCore/RazorEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@ public class RazorEngine : IRazorEngine
public IRazorEngineCompiledTemplate<T> Compile<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null) where T : IRazorEngineTemplate
{
IRazorEngineCompilationOptionsBuilder compilationOptionsBuilder = new RazorEngineCompilationOptionsBuilder();

compilationOptionsBuilder.AddAssemblyReference(typeof(T).Assembly);
compilationOptionsBuilder.Inherits(typeof(T));

builderAction?.Invoke(compilationOptionsBuilder);

MemoryStream memoryStream = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);

return new RazorEngineCompiledTemplate<T>(memoryStream, compilationOptionsBuilder.Options.TemplateNamespace);
if (compilationOptionsBuilder.Options.GeneratePdbStream)
{
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
return new RazorEngineCompiledTemplate<T>(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace, streams.pdb);
}
else
{
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
return new RazorEngineCompiledTemplate<T>(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace);
}
}

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

builderAction?.Invoke(compilationOptionsBuilder);
if (compilationOptionsBuilder.Options.GeneratePdbStream)
{
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
return new RazorEngineCompiledTemplate(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace, streams.pdb);
}
else
{
CompiledStreams streams = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);
return new RazorEngineCompiledTemplate(streams.assembly, compilationOptionsBuilder.Options.TemplateNamespace);
}

MemoryStream memoryStream = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options);

return new RazorEngineCompiledTemplate(memoryStream, compilationOptionsBuilder.Options.TemplateNamespace);
}

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

protected virtual MemoryStream CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options)
protected virtual CompiledStreams CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options, MemoryStream pdbStream = null)
{
templateSource = this.WriteDirectives(templateSource, options);
string projectPath = @".";
string fileName = string.IsNullOrWhiteSpace(options.TemplateFilename) ? Path.GetRandomFileName() + ".cshtml" : options.TemplateFilename;

if (options.GeneratePdbStream)
{
projectPath = Path.GetTempPath();
Directory.CreateDirectory(projectPath);
File.WriteAllText(Path.Combine(projectPath, fileName), templateSource);
}

RazorProjectEngine engine = RazorProjectEngine.Create(
RazorConfiguration.Default,
RazorProjectFileSystem.Create(@"."),
RazorProjectFileSystem.Create(projectPath),
(builder) =>
{
builder.SetNamespace(options.TemplateNamespace);
});

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

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

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

RazorCSharpDocument razorCSharpDocument = codeDocument.GetCSharpDocument();

SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(razorCSharpDocument.GeneratedCode);

CSharpCompilation compilation = CSharpCompilation.Create(
Expand Down Expand Up @@ -102,10 +121,12 @@ protected virtual MemoryStream CreateAndCompileToStream(string templateSource, R
.Concat(options.MetadataReferences)
.ToList(),
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

MemoryStream memoryStream = new MemoryStream();

EmitResult emitResult = compilation.Emit(memoryStream);
CompiledStreams streams = new CompiledStreams();
EmitResult emitResult;
if (options.GeneratePdbStream)
emitResult = compilation.Emit(streams.assembly, streams.pdb);
else
emitResult = compilation.Emit(streams.assembly);

if (!emitResult.Success)
{
Expand All @@ -118,9 +139,10 @@ protected virtual MemoryStream CreateAndCompileToStream(string templateSource, R
throw exception;
}

memoryStream.Position = 0;

return memoryStream;
streams.assembly.Position = 0;
if(options.GeneratePdbStream)
streams.pdb.Position = 0;
return streams;
}

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

return stringBuilder.ToString();
}

protected class CompiledStreams
{
public CompiledStreams()
{
assembly = new MemoryStream();
pdb = new MemoryStream();
}
public MemoryStream assembly {get;set;}
public MemoryStream pdb {get;set;}
}
}
}
}
3 changes: 2 additions & 1 deletion RazorEngineCore/RazorEngineCompilationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class RazorEngineCompilationOptions
public string TemplateNamespace { get; set; } = "TemplateNamespace";
public string TemplateFilename { get; set; } = "";
public string Inherits { get; set; } = "RazorEngineCore.RazorEngineTemplateBase";

///Set to true to generate PDB symbols information along with the assembly for debugging support
public bool GeneratePdbStream {get;set;} = false;
public HashSet<string> DefaultUsings { get; set; } = new HashSet<string>()
{
"System.Linq",
Expand Down
7 changes: 6 additions & 1 deletion RazorEngineCore/RazorEngineCompilationOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,10 @@ private string RenderDeclaringType(Type type)

return parent + "." + type.Name;
}

public void GeneratePdbStream(bool flag)
{
this.Options.GeneratePdbStream = flag;
}
}
}
}
7 changes: 7 additions & 0 deletions RazorEngineCore/RazorEngineCompiledTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templ
Assembly assembly = Assembly.Load(assemblyByteCode.ToArray());
this.templateType = assembly.GetType(templateNamespace + ".Template");
}
internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templateNamespace, MemoryStream pdbByteCode)
{
this.assemblyByteCode = assemblyByteCode;

Assembly assembly = Assembly.Load(assemblyByteCode.ToArray(), pdbByteCode.ToArray());
this.templateType = assembly.GetType(templateNamespace + ".Template");
}

public static IRazorEngineCompiledTemplate LoadFromFile(string fileName, string templateNamespace = "TemplateNamespace")
{
Expand Down
29 changes: 29 additions & 0 deletions RazorEngineCore/RazorEngineCompiledTemplateT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace RazorEngineCore
public class RazorEngineCompiledTemplate<T> : IRazorEngineCompiledTemplate<T> where T : IRazorEngineTemplate
{
private readonly MemoryStream assemblyByteCode;
private readonly MemoryStream pdbByteCode;
private readonly Type templateType;

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

Assembly assembly = Assembly.Load(assemblyByteCode.ToArray());
this.templateType = assembly.GetType($"{templateNamespace}.Template");
}
internal RazorEngineCompiledTemplate(MemoryStream assemblyByteCode, string templateNamespace, MemoryStream pdbByteCode)
{
this.assemblyByteCode = assemblyByteCode;
this.pdbByteCode = pdbByteCode;

Assembly assembly = Assembly.Load(assemblyByteCode.ToArray(), pdbByteCode.ToArray());
this.templateType = assembly.GetType(templateNamespace + ".Template");
}

public static IRazorEngineCompiledTemplate<T> LoadFromFile(string fileName, string templateNamespace = "TemplateNamespace")
Expand Down Expand Up @@ -84,6 +93,24 @@ public Task SaveToFileAsync(string fileName)
}
}

public void SavePdbToFile(string fileName)
{
this.SavePdbToFileAsync(fileName).GetAwaiter().GetResult();
}
public Task SavePdbToFileAsync(string fileName)
{
using (FileStream fileStream = new FileStream(
path: fileName,
mode: FileMode.OpenOrCreate,
access: FileAccess.Write,
share: FileShare.None,
bufferSize: 4096,
useAsync: true))
{
return pdbByteCode.CopyToAsync(fileStream);
}
}

public string Run(Action<T> initializer)
{
return this.RunAsync(initializer).GetAwaiter().GetResult();
Expand All @@ -98,5 +125,7 @@ public async Task<string> RunAsync(Action<T> initializer)

return await instance.ResultAsync();
}


}
}
1 change: 1 addition & 0 deletions RazorEngineCore/RazorEngineCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
</Project>

0 comments on commit 7f18b1c

Please sign in to comment.