Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit d63e486

Browse files
committed
External functions in razor view
Fixes #809
1 parent f7e9575 commit d63e486

File tree

4 files changed

+95
-33
lines changed

4 files changed

+95
-33
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNetCore.Razor;
5+
using Microsoft.AspNetCore.Razor.CodeGenerators;
6+
7+
namespace Microsoft.AspNetCore.Mvc.Razor
8+
{
9+
/// <summary>
10+
/// Specifies the contracts for a Razor host that parses Razor files and generates C# code.
11+
/// </summary>
12+
public interface IMvcRazorHostWithTemplateEngineContext
13+
{
14+
/// <summary>
15+
/// Parses and generates the contents of a Razor file.
16+
/// </summary>
17+
/// <returns>The <see cref="GeneratorResults"/>.</returns>
18+
GeneratorResults GenerateCode(TemplateEngineContext context);
19+
}
20+
}

src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorHost.cs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Linq;
88
using Microsoft.AspNetCore.Mvc.Razor.Directives;
9+
using Microsoft.AspNetCore.Mvc.Razor.Host;
910
using Microsoft.AspNetCore.Mvc.Razor.Internal;
1011
using Microsoft.AspNetCore.Razor;
1112
using Microsoft.AspNetCore.Razor.Chunks;
@@ -20,7 +21,7 @@
2021

2122
namespace Microsoft.AspNetCore.Mvc.Razor
2223
{
23-
public class MvcRazorHost : RazorEngineHost, IMvcRazorHost
24+
public class MvcRazorHost : RazorEngineHost, IMvcRazorHost, IMvcRazorHostWithTemplateEngineContext
2425
{
2526
private const string BaseType = "Microsoft.AspNetCore.Mvc.Razor.RazorPage";
2627
private const string HtmlHelperPropertyName = "Html";
@@ -118,7 +119,7 @@ internal MvcRazorHost(IChunkTreeCache chunkTreeCache, RazorPathNormalizer pathNo
118119
TagHelperOutputContentPropertyName = nameof(TagHelperOutput.Content),
119120
ExecutionContextSetOutputContentAsyncMethodName = nameof(TagHelperExecutionContext.SetOutputContentAsync),
120121
TagHelperAttributeValuePropertyName = nameof(TagHelperAttribute.Value),
121-
})
122+
})
122123
{
123124
BeginContextMethodName = "BeginContext",
124125
EndContextMethodName = "EndContext"
@@ -285,6 +286,23 @@ public GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream
285286
return engine.GenerateCode(inputStream, className, DefaultNamespace, rootRelativePath);
286287
}
287288

289+
/// <inheritdoc />
290+
public GeneratorResults GenerateCode(TemplateEngineContext context)
291+
{
292+
if (context == null)
293+
{
294+
throw new ArgumentNullException(nameof(context));
295+
}
296+
297+
if (string.IsNullOrEmpty(context.ClassName) && !string.IsNullOrEmpty(context.RelativePath))
298+
{
299+
context.ClassName = ParserHelpers.SanitizeClassName(context.RelativePath);
300+
}
301+
302+
var engine = new RazorTemplateEngine(this);
303+
return engine.GenerateCode(context);
304+
}
305+
288306
/// <inheritdoc />
289307
public override RazorParser DecorateRazorParser(RazorParser razorParser, string sourceFileName)
290308
{
@@ -297,6 +315,33 @@ public override RazorParser DecorateRazorParser(RazorParser razorParser, string
297315
return new MvcRazorParser(razorParser, inheritedChunkTrees, DefaultInheritedChunks, ModelExpressionType);
298316
}
299317

318+
public override RazorParser DecorateRazorParser(
319+
RazorParser incomingRazorParser,
320+
TemplateEngineContext context)
321+
{
322+
if (context == null)
323+
{
324+
throw new ArgumentNullException(nameof(context));
325+
}
326+
327+
if (incomingRazorParser == null)
328+
{
329+
throw new ArgumentNullException(nameof(incomingRazorParser));
330+
}
331+
332+
if (string.IsNullOrEmpty(context.RelativePath))
333+
{
334+
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpy, nameof(context.RelativePath));
335+
}
336+
337+
var inheritedChunkTrees = GetInheritedChunkTrees(context.RelativePath);
338+
return new MvcRazorParser(
339+
incomingRazorParser,
340+
inheritedChunkTrees,
341+
DefaultInheritedChunks,
342+
ModelExpressionType);
343+
}
344+
300345
/// <inheritdoc />
301346
public override ParserBase DecorateCodeParser(ParserBase incomingCodeParser)
302347
{

src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationCo
135135
if (!result.Success)
136136
{
137137
return GetCompilationFailedResult(
138-
fileInfo.RelativePath,
138+
fileInfo,
139139
compilationContent,
140140
assemblyName,
141141
result.Diagnostics);
@@ -201,14 +201,14 @@ private CSharpCompilation Rewrite(CSharpCompilation compilation)
201201

202202
// Internal for unit testing
203203
internal CompilationResult GetCompilationFailedResult(
204-
string relativePath,
204+
RelativeFileInfo fileInfo,
205205
string compilationContent,
206206
string assemblyName,
207207
IEnumerable<Diagnostic> diagnostics)
208208
{
209209
var diagnosticGroups = diagnostics
210210
.Where(IsError)
211-
.GroupBy(diagnostic => GetFilePath(relativePath, diagnostic), StringComparer.Ordinal);
211+
.GroupBy(diagnostic => GetFilePath(fileInfo.RelativePath, diagnostic), StringComparer.Ordinal);
212212

213213
var failures = new List<CompilationFailure>();
214214
foreach (var group in diagnosticGroups)
@@ -223,7 +223,7 @@ internal CompilationResult GetCompilationFailedResult(
223223
}
224224
else
225225
{
226-
sourceFileContent = ReadFileContentsSafely(_fileProvider, sourceFilePath);
226+
sourceFileContent = ReadFileContentsSafely(fileInfo.FileInfo);
227227
}
228228

229229
string additionalMessage = null;
@@ -265,9 +265,8 @@ private static bool IsError(Diagnostic diagnostic)
265265
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
266266
}
267267

268-
private static string ReadFileContentsSafely(IFileProvider fileProvider, string filePath)
268+
private static string ReadFileContentsSafely(IFileInfo fileInfo)
269269
{
270-
var fileInfo = fileProvider.GetFileInfo(filePath);
271270
if (fileInfo.Exists)
272271
{
273272
try

src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorCompilationService.cs

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.Linq;
99
using Microsoft.AspNetCore.Diagnostics;
1010
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
11-
using Microsoft.AspNetCore.Mvc.Razor.Internal;
1211
using Microsoft.AspNetCore.Razor;
1312
using Microsoft.AspNetCore.Razor.CodeGenerators;
1413
using Microsoft.Extensions.FileProviders;
@@ -23,6 +22,7 @@ public class RazorCompilationService : IRazorCompilationService
2322
{
2423
private readonly ICompilationService _compilationService;
2524
private readonly IMvcRazorHost _razorHost;
25+
private readonly IMvcRazorHostWithTemplateEngineContext _razorHostWithContext;
2626
private readonly IFileProvider _fileProvider;
2727
private readonly ILogger _logger;
2828

@@ -41,6 +41,7 @@ public RazorCompilationService(
4141
{
4242
_compilationService = compilationService;
4343
_razorHost = razorHost;
44+
_razorHostWithContext = razorHost as IMvcRazorHostWithTemplateEngineContext;
4445
_fileProvider = fileProviderAccessor.FileProvider;
4546
_logger = loggerFactory.CreateLogger<RazorCompilationService>();
4647
}
@@ -53,16 +54,29 @@ public CompilationResult Compile(RelativeFileInfo file)
5354
throw new ArgumentNullException(nameof(file));
5455
}
5556

57+
var filePath = file.FileInfo.PhysicalPath ?? file.RelativePath;
5658
GeneratorResults results;
5759
using (var inputStream = file.FileInfo.CreateReadStream())
5860
{
59-
_logger.RazorFileToCodeCompilationStart(file.RelativePath);
61+
_logger.RazorFileToCodeCompilationStart(filePath);
6062

6163
var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;
6264

63-
results = GenerateCode(file.RelativePath, inputStream);
65+
if (_razorHostWithContext != null)
66+
{
67+
var context = new TemplateEngineContext(inputStream, filePath)
68+
{
69+
RelativePath = file.RelativePath,
70+
};
71+
72+
results = _razorHostWithContext.GenerateCode(context);
73+
}
74+
else
75+
{
76+
results = _razorHost.GenerateCode(filePath, inputStream);
77+
}
6478

65-
_logger.RazorFileToCodeCompilationEnd(file.RelativePath, startTimestamp);
79+
_logger.RazorFileToCodeCompilationEnd(filePath, startTimestamp);
6680
}
6781

6882
if (!results.Success)
@@ -73,36 +87,21 @@ public CompilationResult Compile(RelativeFileInfo file)
7387
return _compilationService.Compile(file, results.GeneratedCode);
7488
}
7589

76-
/// <summary>
77-
/// Generate code for the Razor file at <paramref name="relativePath"/> with content
78-
/// <paramref name="inputStream"/>.
79-
/// </summary>
80-
/// <param name="relativePath">
81-
/// The path of the Razor file relative to the root of the application. Used to generate line pragmas and
82-
/// calculate the class name of the generated type.
83-
/// </param>
84-
/// <param name="inputStream">A <see cref="Stream"/> that contains the Razor content.</param>
85-
/// <returns>A <see cref="GeneratorResults"/> instance containing results of code generation.</returns>
86-
protected virtual GeneratorResults GenerateCode(string relativePath, Stream inputStream)
87-
{
88-
return _razorHost.GenerateCode(relativePath, inputStream);
89-
}
90-
9190
// Internal for unit testing
9291
internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable<RazorError> errors)
9392
{
9493
// If a SourceLocation does not specify a file path, assume it is produced
9594
// from parsing the current file.
9695
var messageGroups = errors
97-
.GroupBy(razorError =>
98-
razorError.Location.FilePath ?? file.RelativePath,
99-
StringComparer.Ordinal);
96+
.GroupBy(
97+
razorError => razorError.Location.FilePath ?? file.RelativePath,
98+
StringComparer.Ordinal);
10099

101100
var failures = new List<CompilationFailure>();
102101
foreach (var group in messageGroups)
103102
{
104103
var filePath = group.Key;
105-
var fileContent = ReadFileContentsSafely(filePath);
104+
var fileContent = ReadFileContentsSafely(file.FileInfo);
106105
var compilationFailure = new CompilationFailure(
107106
filePath,
108107
fileContent,
@@ -127,9 +126,8 @@ private DiagnosticMessage CreateDiagnosticMessage(RazorError error, string fileP
127126
endColumn: error.Location.CharacterIndex + error.Length);
128127
}
129128

130-
private string ReadFileContentsSafely(string relativePath)
129+
private string ReadFileContentsSafely(IFileInfo fileInfo)
131130
{
132-
var fileInfo = _fileProvider.GetFileInfo(relativePath);
133131
if (fileInfo.Exists)
134132
{
135133
try

0 commit comments

Comments
 (0)