我已经实现了类似的东西,但是采用了一种迂回的方法,通过创建一个具有依赖注入的自定义ViewRendering服务,并使用该服务将视图渲染成字符串。 我喜欢这种方法,因为它允许我的应用程序使用视图来完成许多任务,包括电子邮件模板、标签助手以及任何其他需要将视图渲染为字符串的情况,同时也允许我向视图传递模型以获得更动态的元素。
定义服务的接口:
public interface IViewRenderService
{
string RenderView(string viewName);
string RenderView<TModel>(string viewName, TModel model);
}
服务的实现(重要部分):
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;
using System;
using System.IO;
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _viewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public ViewRenderService(IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public string RenderView(string viewName)
{
var actionContext = GetActionContext();
var viewEngineResult = _viewEngine.FindView(actionContext, viewName, false);
if (!viewEngineResult.Success)
{
throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", viewName));
}
var view = viewEngineResult.View;
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary()),
new TempDataDictionary(
actionContext.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
view.RenderAsync(viewContext).GetAwaiter().GetResult();
return output.ToString();
}
}
public string RenderView<TModel>(string viewName, TModel model)
{
var actionContext = GetActionContext();
var viewEngineResult = _viewEngine.FindView(actionContext, viewName, false);
if (!viewEngineResult.Success)
{
throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", viewName));
}
var view = viewEngineResult.View;
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
actionContext.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
view.RenderAsync(viewContext).GetAwaiter().GetResult();
return output.ToString();
}
}
private ActionContext GetActionContext()
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = _serviceProvider;
return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
}
然后在你的 Startup.cs 文件中
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IViewRenderService, ViewRenderService>();
...
}
最后,你可以像以下这样在代码中使用它(例如控制器):
public class TestController : Controller
{
private IViewRenderService viewRenderService;
public TestController(IViewRenderService _viewRenderService)
{
viewRenderService = _viewRenderService;
}
public async Task<IActionResult> Index()
{
var stringOfView = viewRenderService.RenderView("EmailTemplate/EmailConfirmation");
return View();
}
}
您可以将视图放置到其自己的文件夹中的 Views 文件夹下(如上例中所示,视图路径为:/Views/EmailTemplate/EmailConfirmation.cshtml)
如果您的视图需要一个模型,您可以像这样传递它:
var stringOfView = viewRenderService.RenderView("folder/view", model);
希望这可以帮到你!
helper.Partial
这样调用帮助器对象,但不确定在 ASP.NET Core 中是否也能这样做。 - Ehsan Sajjad