From 285f02e63408c4262645bd422201c2a6f55018ac Mon Sep 17 00:00:00 2001 From: Scott Sauber Date: Thu, 5 Jul 2018 21:11:01 -0500 Subject: [PATCH] Add RazorViewToStringRenderer --- .../Services/RazorViewToStringRenderer.cs | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/RazorHtmlEmails.RazorClassLib/Services/RazorViewToStringRenderer.cs diff --git a/src/RazorHtmlEmails.RazorClassLib/Services/RazorViewToStringRenderer.cs b/src/RazorHtmlEmails.RazorClassLib/Services/RazorViewToStringRenderer.cs new file mode 100644 index 0000000..8b89d85 --- /dev/null +++ b/src/RazorHtmlEmails.RazorClassLib/Services/RazorViewToStringRenderer.cs @@ -0,0 +1,97 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Routing; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace RazorHtmlEmails.RazorClassLib.Services +{ + // Code from: https://github.com/aspnet/Entropy/blob/dev/samples/Mvc.RenderViewToString/RazorViewToStringRenderer.cs + + public class RazorViewToStringRenderer : IRazorViewToStringRenderer + { + private IRazorViewEngine _viewEngine; + private ITempDataProvider _tempDataProvider; + private IServiceProvider _serviceProvider; + + public RazorViewToStringRenderer( + IRazorViewEngine viewEngine, + ITempDataProvider tempDataProvider, + IServiceProvider serviceProvider) + { + _viewEngine = viewEngine; + _tempDataProvider = tempDataProvider; + _serviceProvider = serviceProvider; + } + + public async Task RenderViewToStringAsync(string viewName, TModel model) + { + var actionContext = GetActionContext(); + var view = FindView(actionContext, viewName); + + using (var output = new StringWriter()) + { + var viewContext = new ViewContext( + actionContext, + view, + new ViewDataDictionary( + metadataProvider: new EmptyModelMetadataProvider(), + modelState: new ModelStateDictionary()) + { + Model = model + }, + new TempDataDictionary( + actionContext.HttpContext, + _tempDataProvider), + output, + new HtmlHelperOptions()); + + await view.RenderAsync(viewContext); + + return output.ToString(); + } + } + + private IView FindView(ActionContext actionContext, string viewName) + { + var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true); + if (getViewResult.Success) + { + return getViewResult.View; + } + + var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: true); + if (findViewResult.Success) + { + return findViewResult.View; + } + + var searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations); + var errorMessage = string.Join( + Environment.NewLine, + new[] { $"Unable to find view '{viewName}'. The following locations were searched:" }.Concat(searchedLocations)); ; + + throw new InvalidOperationException(errorMessage); + } + + private ActionContext GetActionContext() + { + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = _serviceProvider; + return new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + } + + } + public interface IRazorViewToStringRenderer + { + Task RenderViewToStringAsync(string viewName, TModel model); + } +}