Created
June 20, 2017 16:15
-
-
Save snboisen/fa933407a84a8273df98575fc07ff47d to your computer and use it in GitHub Desktop.
A template loader for Stubble based on ASP.NET Core abstractions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Concurrent; | |
using System.IO; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.Extensions.Options; | |
using Stubble.Core.Interfaces; | |
namespace TeamString.Admin.Email | |
{ | |
/// <summary> | |
/// A template loader for Stubble that locates templates based on a base path relative to the | |
/// webapp content root. This loader integrates much better with ASP.NET Core apps than the | |
/// FileSystemLoader provided in Stubble extensions. | |
/// </summary> | |
public sealed class AspNetCoreTemplateLoader : IStubbleLoader | |
{ | |
private readonly string templateBasePath; | |
private readonly ConcurrentDictionary<string, string> templateCache; | |
public AspNetCoreTemplateLoader(IOptions<StubbleOptions> options, IHostingEnvironment hostEnv) | |
{ | |
this.templateBasePath = Path.Combine(hostEnv.ContentRootPath, options.Value.TemplateBasePath); | |
this.templateCache = new ConcurrentDictionary<string, string>(); | |
} | |
private AspNetCoreTemplateLoader(string templateBasePath, ConcurrentDictionary<string, string> templateCache) | |
{ | |
this.templateBasePath = templateBasePath; | |
this.templateCache = templateCache; | |
} | |
public IStubbleLoader Clone() | |
{ | |
return new AspNetCoreTemplateLoader(templateBasePath, templateCache); | |
} | |
public string Load(string name) | |
{ | |
string template = null; | |
if (!templateCache.TryGetValue(name, out template)) | |
{ | |
template = LoadTextFile(name); | |
templateCache.AddOrUpdate(name, template, (k, v) => template); | |
} | |
return template; | |
} | |
public ValueTask<string> LoadAsync(string name) | |
{ | |
string template = null; | |
if (templateCache.TryGetValue(name, out template)) | |
{ | |
return new ValueTask<string>(template); | |
} | |
else | |
{ | |
return new ValueTask<string>(LoadFromFileAsync(name)); | |
} | |
} | |
// TODO: Move this method inside LoadAsync as a local function once we move to C# 7 | |
// See: http://thebillwagner.com/Blog/Item/2016-03-02-C7FeatureProposalLocalFunctions | |
private async Task<string> LoadFromFileAsync(string name) | |
{ | |
string template = await LoadTextFileAsync(name); | |
templateCache.AddOrUpdate(name, template, (k, v) => template); | |
return template; | |
} | |
private string GetFullPath(string templateName) => Path.Combine(templateBasePath, templateName); | |
private string LoadTextFile(string templateName) => File.ReadAllText(GetFullPath(templateName), Encoding.UTF8); | |
private async Task<string> LoadTextFileAsync(string templateName) | |
{ | |
using (var file = new FileStream(GetFullPath(templateName), FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true)) | |
using (var reader = new StreamReader(file, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 4096, leaveOpen: true)) | |
{ | |
return await reader.ReadToEndAsync(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment