You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Razor Pages中如何将带ViewModel的页面渲染为HTML字符串用于邮件?

Solution for Rendering Razor Page to HTML String in ASP.NET Core

Step 1: Implement a Razor Page Rendering Service

Create a reusable service that handles executing the PageModel's logic and rendering the Razor page to a string. This ensures you reuse the existing OnGet data fetching and calculation logic.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.IO;
using System.Threading.Tasks;

public interface IRazorPageRenderer
{
    Task<string> RenderPageToStringAsync<TModel>(string pagePath, TModel model) where TModel : class;
}

public class RazorPageRenderer : IRazorPageRenderer
{
    private readonly IRazorViewEngine _viewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public RazorPageRenderer(IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHttpContextAccessor httpContextAccessor)
    {
        _viewEngine = viewEngine;
        _tempDataProvider = tempDataProvider;
        _serviceProvider = serviceProvider;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<string> RenderPageToStringAsync<TModel>(string pagePath, TModel model) where TModel : class
    {
        // Initialize context
        var httpContext = _httpContextAccessor.HttpContext ?? new DefaultHttpContext { RequestServices = _serviceProvider };
        var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor());

        // Locate the target Razor page
        var pageResult = _viewEngine.FindPage(actionContext, pagePath);
        if (!pageResult.Success)
        {
            throw new InvalidOperationException($"Page not found at path: {pagePath}");
        }

        // Set up view data and temp data
        var viewData = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary())
        {
            Model = model
        };
        var tempData = new TempDataDictionary(httpContext, _tempDataProvider);

        // Prepare view context
        var viewContext = new ViewContext(
            actionContext,
            pageResult.Page,
            viewData,
            tempData,
            new StringWriter(),
            new HtmlHelperOptions()
        );

        // Execute PageModel logic (OnGetAsync)
        if (pageResult.Page is PageModel pageModel)
        {
            pageModel.PageContext = new PageContext(actionContext);
            pageModel.ViewData = viewData;
            pageModel.TempData = tempData;
            pageModel.Url = new UrlHelper(actionContext);

            // Inject any required dependencies into the PageModel (e.g., database context)
            // Example: pageModel.DbContext = _serviceProvider.GetRequiredService<YourDbContext>();

            await pageModel.OnGetAsync();
        }

        // Render page to string
        await pageResult.Page.ExecuteAsync(viewContext);
        return ((StringWriter)viewContext.Writer).ToString();
    }
}

Step 2: Register the Service in Dependency Injection

Add the service to your app's DI container (in Program.cs for .NET 6+):

builder.Services.AddScoped<IRazorPageRenderer, RazorPageRenderer>();
builder.Services.AddHttpContextAccessor();

Step 3: Use the Service to Generate Invoice HTML

In your target page's PageModel, inject the renderer and call it to get the HTML string for the email body.

Assuming your layout-free invoice page is Pages/InvoicePrint.cshtml with PageModel InvoicePrintModel:

public class EmailSenderPageModel : PageModel
{
    private readonly IRazorPageRenderer _pageRenderer;

    public EmailSenderPageModel(IRazorPageRenderer pageRenderer)
    {
        _pageRenderer = pageRenderer;
    }

    public async Task<IActionResult> OnPostSendInvoiceAsync(int invoiceId)
    {
        // Initialize the invoice PageModel and pass required parameters
        var invoiceModel = new InvoicePrintModel { InvoiceId = invoiceId };

        // Render the invoice page to HTML
        string invoiceHtml = await _pageRenderer.RenderPageToStringAsync("/Pages/InvoicePrint", invoiceModel);

        // Use the HTML as email body (integrate with your email service)
        // Example: await _emailService.SendAsync("customer@example.com", "Your Invoice", invoiceHtml);

        return RedirectToPage("/Invoices");
    }
}

Critical Fixes for Null Reference Errors

  • Inject PageModel Dependencies: If your InvoicePrintModel requires services (like a database context), resolve them via _serviceProvider in the renderer before calling OnGetAsync.
  • Route Data Handling: If your invoice page uses route parameters, populate pageModel.PageContext.RouteData.Values with the required values in the renderer.
  • Confirm Layout-Free Setup: Ensure InvoicePrint.cshtml includes @{ Layout = null; } to exclude site layouts from the email HTML.

内容的提问来源于stack exchange,提问作者David Bahler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:55:41