Render Razor View to String in ASP.NET Core

Return View as String in .NET Core

Thanks to Paris Polyzos and his article.

I'm re-posting his code here, just in case the original post got removed for any reason.

Create Service in file viewToString.cs as below code:

using System;
using System.IO;
using System.Threading.Tasks;
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.ViewFeatures;
using Microsoft.AspNetCore.Routing;
 
namespace WebApplication.Services
{
    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();
            }
        }
    }
}

2. Add the service to the Startup.cs file, as:

using WebApplication.Services;

public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IViewRenderService, ViewRenderService>();
}

3. Add "preserveCompilationContext": true to the buildOptions in the project.json, so the file looks like:

{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.Mvc": "1.0.1"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.1"
}
},
"imports": "dnxcore50"
}
}
}

4. Define you model, for example:

public class InviteViewModel {
public string UserId {get; set;}
public string UserName {get; set;}
public string ReferralCode {get; set;}
public int Credits {get; set;}
}

5. Create your Invite.cshtml for example:

@{
ViewData["Title"] = "Contact";
}
@ViewData["Title"].
user id: @Model.UserId

6. In the Controller:

a. Define the below at the beginning:

private readonly IViewRenderService _viewRenderService;

public RenderController(IViewRenderService viewRenderService)
{
_viewRenderService = viewRenderService;
}

b. Call and return the view with model as below:

var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
return Content(result);

c. The FULL controller example, could be like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using WebApplication.Services;

namespace WebApplication.Controllers
{
[Route("render")]
public class RenderController : Controller
{
private readonly IViewRenderService _viewRenderService;

public RenderController(IViewRenderService viewRenderService)
{
_viewRenderService = viewRenderService;
}

[Route("invite")]
public async Task<IActionResult> RenderInviteView()
{
ViewData["Message"] = "Your application description page.";
var viewModel = new InviteViewModel
{
UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
UserName = "Hasan",
ReferralCode = "55e12b710f78",
Credits = 10
};
 
var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
return Content(result);
}

public class InviteViewModel {
public string UserId {get; set;}
public string UserName {get; set;}
public string ReferralCode {get; set;}
public int Credits {get; set;}
}
}

ASP.NET CORE Render Razor View to string with controller parameters

I think you may understand the usage of RenderRazorViewToString.This method is called by the following code:

Helper.RenderRazorViewToString(controller, "PartialViewName", model);

The second parameter is not the method name,it is the partial view name.It would not get to the IndexPartial method.

What you want is to parse the partial view with model to string.The model data get by manipulating query by searchValue and filterValue.

To meet your requirement,what you need do should be like below:

public string IndexPartial(string? searchValue, string? filterValue)
{
var model = _context.Pupils
.Where(a => a.Name.Contains(searchValue)&& a.Email.Contains(filterValue))
.FirstOrDefault(); //Manipulate query by searchValue and filterValue

//pass the correct model to the RenderRazorViewToString method
//then it would render the partial view to the correct string
var data = Helper.RenderRazorViewToString(this, "PartialViewName", model);
return data;
}

Result:
Sample Image

Render Razor View to string in ASP.NET Core

UPDATE July, 2016

Working fine on the following versions 1.0.0, RC2


Who's targeting aspnetcore RC2, this snippet might help you:

  • Create a separate Service, so you can use it either if you are not in a controller context, e.g. from a command line or on a queue runner, etc ...
  • Register this service in your IoC container in the Startup class

https://gist.github.com/ahmad-moussawi/1643d703c11699a6a4046e57247b4d09

Usage

// using a Model
string html = view.Render("Emails/Test", new Product("Apple"));

// using a Dictionary<string, object>
var viewData = new Dictionary<string, object>();
viewData["Name"] = "123456";

string html = view.Render("Emails/Test", viewData);

Notes

Links in Razor are rendered as relative URL, so this will not work on external views (like emails, etc ...).

As for now am generating the link on the controller and pass it to the view through the ViewModel.

Credit

The source is extracted from (Thanks To @pholly): https://github.com/aspnet/Entropy/blob/dev/samples/Mvc.RenderViewToString/RazorViewToStringRenderer.cs)

Pre-compiled Razor view to string with ASP.NET Core

You have to implement an IViewRenderService and register is in your Startup.cs. Then add a function like this:

public class ViewRenderService : IViewRenderService
{
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
private readonly HttpContext _context;
private readonly ICompositeViewEngine _viewEngine;
private const string ControllerStr = "controller";

public ViewRenderService(
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider,
IHttpContextAccessor accessor,
ICompositeViewEngine viewEngine)
{
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
_context = accessor.HttpContext;
_viewEngine = viewEngine;
}

public async Task<string> RenderToStringAsync(string viewName, object model)
{
return await RenderToStringAsync(viewName, model, null);
}

public async Task<string> RenderToStringAsync(string viewName, object model, ViewDataDictionary viewDataDictionary)
{
var controller = string.Empty;
viewName = viewName?.TrimStart(new char[] { '/' });
Regex rex = new Regex(@"^(\w+)\/(.*)$");
Match match = rex.Match(viewName);
if (match.Success)
{
controller = match.Groups[1].Value;
viewName = match.Groups[2].Value;
}

var routeData = new RouteData();
routeData.Values.Add(ControllerStr, controller);
var actionContext = new ActionContext(_context, routeData, new ActionDescriptor());

var viewResult = _viewEngine.FindView(actionContext, viewName, false);

if (viewResult.View == null)
{
Console.WriteLine($"Searched the following locations: {string.Join(", ", viewResult.SearchedLocations)} for folder \"{controller}\" and view \"{viewName}\"");
throw new ArgumentNullException($"{viewName} does not match any available view");
}

var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};

if (viewDataDictionary != null)
{
foreach (var obj in viewDataDictionary)
{
viewDictionary.Add(obj);
}
}

using (var sw = new StringWriter())
{
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(_context, _tempDataProvider),
sw,
new HtmlHelperOptions()
);
viewContext.RouteData = _context.GetRouteData();

await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}

Render Razor view to string in ASP.NET 5

I use the following types injected from the IServiceProvider:

ICompositeViewEngine viewEngine;
ITempDataProvider tempDataProvider;
IHttpContextAccessor httpContextAccessor;

I render the content using the following method:

private async Task<string> RenderView(string path, ViewDataDictionary viewDataDictionary, ActionContext actionContext)
{
using (var sw = new System.IO.StringWriter())
{
var viewResult = viewEngine.FindView(actionContext, path);

var viewContext = new ViewContext(actionContext, viewResult.View, viewDataDictionary, new TempDataDictionary(httpContextAccessor, tempDataProvider), sw);

await viewResult.View.RenderAsync(viewContext);
sw.Flush();

if (viewContext.ViewData != viewDataDictionary)
{
var keys = viewContext.ViewData.Keys.ToArray();
foreach (var key in keys)
{
viewDataDictionary[key] = viewContext.ViewData[key];
}
}

return sw.ToString();
}
}

I call it like this:

var path = "~/Views/Home/Index.cshtml";
var viewDataDictionary = new ViewDataDictionary(new Microsoft.AspNet.Mvc.ModelBinding.EmptyModelMetadataProvider(), new Microsoft.AspNet.Mvc.ModelBinding.ModelStateDictionary());
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new Microsoft.AspNet.Routing.RouteData(), new ActionDescriptor());
viewDataDictionary.Model = null;
var text = await RenderView(path, viewDataDictionary, actionContext);

Of course, my viewDataDictionary and actionContext variables are set by another method for encapsulation. A modification to the new ViewDataDictionary line can result in a typed Model being bound to your View if you choose.

This code uses heavy usings, I think I've listed them below. Otherwise, VS2015 is pretty good about finding them.

using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;

This was written under beta-3; it still builds, but some things may change. I'll try to come back here to update if it does.

Render Razor View Page as string from WebApi Core

If you use .Net Core, there is a NuGet package you can easily install: RazorEngine.NetCore

The documentation is good but here is the short version:

Include the library:

    using RazorEngine;
using RazorEngine.Templating;

Get your razor html

        string razorView= "Hello @Model.Name, welcome to RazorEngine!";

If it's in a file you could use File.ReadAllText

        string razorView = await File.ReadAllTextAsync(filePath);

and compile:

string result = Engine.Razor.RunCompile(razorView, "templateKey", null, null);

And if you want to inject some object, pass it in the 4th argument

Render Partial View to HTML string in ASP.NET Core 2.2

Why Json result with html string? You can return a partial view directly to return html.

public IActionResult GetUpsertPartialView(MessageBoard messageBoard)
{

return PartialView("someviewname", messageBoard);
}


Related Topics



Leave a reply



Submit