Last active
August 27, 2020 03:20
-
-
Save wmeints/c547209b69128e4ee537cb8f35c3a6dc to your computer and use it in GitHub Desktop.
A template service based on the ASP.NET Core razor engine
This file contains 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
/// <summary> | |
/// Renders email content based on razor templates | |
/// </summary> | |
public interface ITemplateService | |
{ | |
/// <summary> | |
/// Renders a template given the provided view model | |
/// </summary> | |
/// <typeparam name="TViewModel"></typeparam> | |
/// <param name="filename">Filename of the template to render</param> | |
/// <param name="viewModel">View model to use for rendering the template</param> | |
/// <returns>Returns the rendered template content</returns> | |
Task<string> RenderTemplateAsync<TViewModel>(string filename, TViewModel viewModel); | |
} |
This file contains 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
public class TemplateService: ITemplateService | |
{ | |
private IRazorViewEngine _viewEngine; | |
private readonly IServiceProvider _serviceProvider; | |
private readonly ITempDataProvider _tempDataProvider; | |
public TemplateService(IRazorViewEngine viewEngine, IServiceProvider serviceProvider, ITempDataProvider tempDataProvider) | |
{ | |
_viewEngine = viewEngine; | |
_serviceProvider = serviceProvider; | |
_tempDataProvider = tempDataProvider; | |
} | |
public async Task<string> RenderTemplateAsync<TViewModel>(string filename, TViewModel viewModel) | |
{ | |
var httpContext = new DefaultHttpContext | |
{ | |
RequestServices = _serviceProvider | |
}; | |
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); | |
using (var outputWriter = new StringWriter()) | |
{ | |
var viewResult = _viewEngine.FindView(actionContext, filename, false); | |
var viewDictionary = new ViewDataDictionary<TViewModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) | |
{ | |
Model = viewModel | |
}; | |
var tempDataDictionary = new TempDataDictionary(httpContext, _tempDataProvider); | |
if (!viewResult.Success) | |
{ | |
throw new TemplateServiceException($"Failed to render template {filename} because it was not found."); | |
} | |
try | |
{ | |
var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, | |
tempDataDictionary, outputWriter, new HtmlHelperOptions()); | |
await viewResult.View.RenderAsync(viewContext); | |
} | |
catch (Exception ex) | |
{ | |
throw new TemplateServiceException("Failed to render template due to a razor engine failure", ex); | |
} | |
return outputWriter.ToString(); | |
} | |
} | |
} |
This file contains 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
/// <summary> | |
/// Gets thrown when the template service was unable to render the template | |
/// </summary> | |
public class TemplateServiceException: Exception | |
{ | |
/// <summary> | |
/// Initializes a new instance of <see cref="TemplateServiceException"/> | |
/// </summary> | |
/// <param name="message"></param> | |
public TemplateServiceException(string message) : base(message) | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of <see cref="TemplateServiceException"/> | |
/// </summary> | |
/// <param name="message"></param> | |
/// <param name="innerException"></param> | |
public TemplateServiceException(string message, Exception innerException) : base(message, innerException) | |
{ | |
} | |
} |
Thanks. It's working.
This works great if I run it with dotnet run or inside of visual studio. But if I publish the app I get an error that the "Template" was not found. Using .net core 2.0 the views will be pre-compiled. Do I need to copy the files separately?
[Edit]
Okay, so it seems that it will not work with PreCompiled views. Had to add the following to my csproj
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
Nice code, worked perfectly. I just changed a little to use a list of viewmodels. Thanks
In rendering the view I use Viewbag and javascript in the view. Is that something that can be used as well and how do I specify those?
any thoughts? ideas?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For anyone that comes across this and is wondering why their models are null in the view, causing exceptions, just add this line in, after line 26 in TemplateService.cs:
viewDictionary.Model = viewModel;