diff --git a/RazorEngineCore.Tests/TestCompileAndRun.cs b/RazorEngineCore.Tests/TestCompileAndRun.cs index 4df8090..2103666 100644 --- a/RazorEngineCore.Tests/TestCompileAndRun.cs +++ b/RazorEngineCore.Tests/TestCompileAndRun.cs @@ -13,6 +13,7 @@ namespace RazorEngineCore.Tests { using System.Runtime.InteropServices; + using System.Threading; [TestClass] public class TestCompileAndRun @@ -728,6 +729,66 @@ @using TestAssembly Assert.AreEqual(expected, actual); } + [TestMethod] + public void TestCompileCancellation_DynamicModel() + { + RazorEngine razorEngine = new RazorEngine(); + using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) + { + cancellationSource.Cancel(); + + Assert.ThrowsException(() => + { + IRazorEngineCompiledTemplate template = razorEngine.Compile("Hello @Model.Name", cancellationToken: cancellationSource.Token); + }); + } + } + + [TestMethod] + public async Task TestCompileCancellation_DynamicModelAsync() + { + RazorEngine razorEngine = new RazorEngine(); + using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) + { + cancellationSource.Cancel(); + + await Assert.ThrowsExceptionAsync(async () => + { + IRazorEngineCompiledTemplate template = await razorEngine.CompileAsync("Hello @Model.Name", cancellationToken: cancellationSource.Token); + }); + } + } + + [TestMethod] + public void TestCompileCancellation_TypedModel1() + { + RazorEngine razorEngine = new RazorEngine(); + using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) + { + cancellationSource.Cancel(); + + Assert.ThrowsException(() => + { + IRazorEngineCompiledTemplate template = razorEngine.Compile("Hello @A @B @(A + B) @C @Decorator(\"777\")", cancellationToken: cancellationSource.Token); + }); + } + } + + [TestMethod] + public async Task TestCompileCancellation_TypedModel1Async() + { + RazorEngine razorEngine = new RazorEngine(); + using (CancellationTokenSource cancellationSource = new CancellationTokenSource()) + { + cancellationSource.Cancel(); + + await Assert.ThrowsExceptionAsync(async () => + { + IRazorEngineCompiledTemplate template = await razorEngine.CompileAsync("Hello @A @B @(A + B) @C @Decorator(\"777\")", cancellationToken: cancellationSource.Token); + }); + } + } + private static List GetMetadataReferences() { if (RuntimeInformation.FrameworkDescription.StartsWith( diff --git a/RazorEngineCore/IRazorEngine.cs b/RazorEngineCore/IRazorEngine.cs index 3d0b5c2..d5b07de 100644 --- a/RazorEngineCore/IRazorEngine.cs +++ b/RazorEngineCore/IRazorEngine.cs @@ -1,18 +1,19 @@ using System; +using System.Threading; using System.Threading.Tasks; namespace RazorEngineCore { public interface IRazorEngine { - IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null) + IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null, CancellationToken cancellationToken = default) where T : IRazorEngineTemplate; - - Task> CompileAsync(string content, Action builderAction = null) + + Task> CompileAsync(string content, Action builderAction = null, CancellationToken cancellationToken = default) where T : IRazorEngineTemplate; - IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null); + IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null, CancellationToken cancellationToken = default); - Task CompileAsync(string content, Action builderAction = null); + Task CompileAsync(string content, Action builderAction = null, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/RazorEngineCore/RazorEngine.cs b/RazorEngineCore/RazorEngine.cs index bdad3cc..feb2e03 100644 --- a/RazorEngineCore/RazorEngine.cs +++ b/RazorEngineCore/RazorEngine.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; @@ -15,7 +16,7 @@ namespace RazorEngineCore { public class RazorEngine : IRazorEngine { - public IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null) where T : IRazorEngineTemplate + public IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null, CancellationToken cancellationToken = default) where T : IRazorEngineTemplate { IRazorEngineCompilationOptionsBuilder compilationOptionsBuilder = new RazorEngineCompilationOptionsBuilder(); compilationOptionsBuilder.AddAssemblyReference(typeof(T).Assembly); @@ -23,33 +24,34 @@ public IRazorEngineCompiledTemplate Compile(string content, Action(meta); } - public Task> CompileAsync(string content, Action builderAction = null) where T : IRazorEngineTemplate + public Task> CompileAsync(string content, Action builderAction = null, CancellationToken cancellationToken = default) where T : IRazorEngineTemplate { - return Task.Factory.StartNew(() => this.Compile(content: content, builderAction: builderAction)); + return Task.Factory.StartNew(() => this.Compile(content: content, builderAction: builderAction, cancellationToken: cancellationToken)); } - public IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null) + public IRazorEngineCompiledTemplate Compile(string content, Action builderAction = null, CancellationToken cancellationToken = default) { IRazorEngineCompilationOptionsBuilder compilationOptionsBuilder = new RazorEngineCompilationOptionsBuilder(); compilationOptionsBuilder.Inherits(typeof(RazorEngineTemplateBase)); builderAction?.Invoke(compilationOptionsBuilder); - - RazorEngineCompiledTemplateMeta meta = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options); + + RazorEngineCompiledTemplateMeta meta = this.CreateAndCompileToStream(content, compilationOptionsBuilder.Options, cancellationToken); return new RazorEngineCompiledTemplate(meta); } - public Task CompileAsync(string content, Action builderAction = null) + public Task CompileAsync(string content, Action builderAction = null, CancellationToken cancellationToken = default) { - return Task.Factory.StartNew(() => this.Compile(content: content, builderAction: builderAction)); + return Task.Factory.StartNew(() => this.Compile(content: content, builderAction: builderAction, cancellationToken: cancellationToken)); } - protected virtual RazorEngineCompiledTemplateMeta CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options) + protected virtual RazorEngineCompiledTemplateMeta CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options, CancellationToken cancellationToken) + { templateSource = this.WriteDirectives(templateSource, options); string projectPath = @"."; @@ -75,9 +77,9 @@ protected virtual RazorEngineCompiledTemplateMeta CreateAndCompileToStream(strin new List()); - RazorCSharpDocument razorCSharpDocument = codeDocument.GetCSharpDocument(); - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(razorCSharpDocument.GeneratedCode); + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(razorCSharpDocument.GeneratedCode, cancellationToken: cancellationToken); + CSharpCompilation compilation = CSharpCompilation.Create( fileName, @@ -110,7 +112,8 @@ protected virtual RazorEngineCompiledTemplateMeta CreateAndCompileToStream(strin MemoryStream assemblyStream = new MemoryStream(); MemoryStream pdbStream = options.IncludeDebuggingInfo ? new MemoryStream() : null; - EmitResult emitResult = compilation.Emit(assemblyStream, pdbStream); + EmitResult emitResult = compilation.Emit(assemblyStream, pdbStream, cancellationToken: cancellationToken); + if (!emitResult.Success) {