Render Razor View as String
The following demonstrates rendering a Razor view in a Hosted Background service of an ASP .Net 8 API using the Default HttpContext. Even though it's an API project, the Background service still doesn't have "access" to a live request, so there's no HttpContext available.
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 API.Services
{
public class ViewRenderService
{
private readonly IRazorViewEngine razorViewEngine;
private readonly ITempDataProvider tempDataProvider;
private readonly IServiceProvider serviceProvider;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
this.razorViewEngine = razorViewEngine;
this.tempDataProvider = tempDataProvider;
this.serviceProvider = serviceProvider;
}
public async Task RenderToStringAsync(string viewName, object model)
{
return await RenderToStringAsync(viewName, model, new ModelStateDictionary());
}
public async Task RenderToStringAsync(string viewName, object model, ModelStateDictionary modelState)
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = serviceProvider;
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = FindView(actionContext, viewName);
if (viewResult == null)
{
throw new ArgumentNullException($"View {viewName} not found.");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
sw,
new HtmlHelperOptions()
);
await viewResult.RenderAsync(viewContext);
return sw.ToString();
}
}
private IView FindView(ActionContext actionContext, string viewName)
{
var getViewResult = razorViewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: false);
if (getViewResult.Success)
{
return getViewResult.View;
}
var findViewResult = razorViewEngine.FindView(actionContext, viewName, isMainPage: false);
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);
}
}
}