Render ViewComponent as string
Rendering a View to a string is covered here. Turns out there’s a very similar approach to rendering a ViewComponent as a string. Here’s the code, thanks to this comment on the ASP.NET forums:
public interface IViewRenderService { Task<string> RenderToStringAsync(string viewName, object model); } public class ViewRenderService : IViewRenderService { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; } public async Task<string> RenderToStringAsync(string viewName, object model) { var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider }; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); using var sw = new StringWriter(); var viewResult = _razorViewEngine.FindView(actionContext, viewName, false); if (viewResult.View == null) { throw new ArgumentNullException($"{viewName} does not match any available view"); } var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model }; var viewContext = new ViewContext( actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions() ); await viewResult.View.RenderAsync(viewContext); return sw.ToString(); } } string result = await _viewRenderService.RenderToStringAsync("Shared/Components/Foo/Default", model); // Don't forget to register the service so you can use constructor injection in your controller: public void ConfigureServices(IServiceCollection services) { /// ... services.AddScoped<IViewRenderService, ViewRenderService>(); }