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:
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
How Should Anonymous Types Be Used in C#
What Is the Static Variable Initialization Order Across Classes in C#
Binding Listbox to List<Object> in Winforms
How to Prevent a SQL Injection Escaping Strings
.Net 4.0 and the Dreaded Onuserpreferencechanged Hang
Should I Store My Images in the Database or Folders
Create Dynamic Buttons in a Grid Layout - Create a Magic Square Ui
Best Programming Practice of Using Dropdownlist in ASP.NET MVC
Date of Birth Validation Keeps Showing
How Accurate Is Thread.Sleep(Timespan)
Getting Attribute Value of an Xml Document Using C#
Why Doesn't Xmlserializer Support Dictionary
How to Execute Task in the Wpf Background While Able to Provide Report and Allow Cancellation