-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathRazorViewEngine.cs
65 lines (57 loc) · 3.06 KB
/
RazorViewEngine.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using Microsoft.Extensions.Logging;
using MiniWebServer.Mvc.Abstraction;
using MiniWebServer.Mvc.Abstraction.ViewContent;
using MiniWebServer.Mvc.MiniRazorEngine;
using MiniWebServer.Mvc.MiniRazorEngine.Parser;
namespace MiniWebServer.Mvc.RazorEngine
{
public class MiniRazorViewEngine(MiniRazorViewEngineOptions options, ILogger<MiniRazorViewEngine> logger, ITemplateParser templateParser, IViewFinder? viewFinder = default) : IViewEngine
{
public const string DefaultViewFolder = "Views";
private readonly MiniRazorViewEngineOptions options = options ?? throw new ArgumentNullException(nameof(options));
private readonly IViewFinder viewFinder = viewFinder ?? new DefaultViewFinder(DefaultViewFolder);
private readonly ITemplateParser templateParser = templateParser ?? throw new ArgumentNullException(nameof(templateParser));
public async Task<IViewContent?> RenderAsync(ActionResultContext context, string viewName, object? model, IDictionary<string, object> viewData)
{
// TODO: we should support caching compiled template, we will need to redesign a bit in this part
try
{
/*
How to render a view using razor?
- find a template string by view name
- compile the template to C# code
- compile the C# code to an assembly
- load the assembly and call it's InvokeAsync() function
- send back InvokeAsync result to client
What problems can we have?
- we need caching compiled C# files
- we need to design a parent class for compiled C# classes
- we will need to find a proper way to stream data generated by InvokeAsync back to client, taking everything and send at once back to
client using a StringContent is not a good idea
*/
var template = viewFinder.Find(context, viewName);
if (template == null)
{
logger.LogError("View not found: {v}", viewName);
return await Task.FromResult(new InternalErrorViewContent());
}
var parseResult = await templateParser.ParseAsync(viewName, template, model);
if (parseResult.Compiled)
{
string compiledContent = parseResult.CompiledContent;
return await Task.FromResult(new StringViewContent(compiledContent));
}
else
{
logger.LogError(parseResult.Exception, "Error parsing view: {v}", viewName);
return await Task.FromResult(new InternalErrorViewContent(parseResult.Exception?.ToString() ?? string.Empty));
}
}
catch (Exception ex)
{
logger.LogError(ex, "Error rendering view");
return await Task.FromResult(new InternalErrorViewContent(ex.Message + "\r\n" + ex.StackTrace));
}
}
}
}