在.NET Core中将视图返回为字符串
我发现了一些文章如何在ASP.NET中将视图返回到字符串,但无法转换为能够使用.NET Core运行它
public static string RenderViewToString(this Controller controller, string viewName, object model) { var context = controller.ControllerContext; if (string.IsNullOrEmpty(viewName)) viewName = context.RouteData.GetRequiredString("action"); var viewData = new ViewDataDictionary(model); using (var sw = new StringWriter()) { var viewResult = ViewEngines.Engines.FindPartialView(context, viewName); var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw); viewResult.View.Render(viewContext, sw); return sw.GetStringBuilder().ToString(); } }
假设能够使用以下控制器从控制器调用:
var strView = this.RenderViewToString("YourViewName", yourModel);
当我尝试将上述内容运行到.NET Core时,我遇到了很多编译错误。
我试图将其转换为使用.NET Core,但失败了,任何人都可以帮助提及所需的using ..
和所需的"dependencies": { "Microsoft.AspNetCore.Mvc": "1.1.0", ... },
在project.json
。
其他一些示例代码在这里 , 这里和这里
注意我需要解决方案来将视图转换为.NET Core中的string
,无论相同的代码是否已转换,或者其他方式可以执行此操作。
感谢Paris Polyzos和他的文章 。
我在这里重新发布他的代码,以防原始post因任何原因被删除。
在文件viewToString.cs
创建Service
,如下代码:
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 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 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(); } } } }
-
将服务添加到
Startup.cs
文件中,如下所示:using WebApplication.Services; public void ConfigureServices(IServiceCollection services) { ... services.AddScoped
(); }
将"preserveCompilationContext": true
添加到project.json
的buildOptions
,因此该文件如下所示:
{ "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" } } }
-
定义
model
,例如:public class InviteViewModel { public string UserId {get; set;} public string UserName {get; set;} public string ReferralCode {get; set;} public int Credits {get; set;} }
-
例如,创建
Invite.cshtml
:@{ ViewData["Title"] = "Contact"; } @ViewData["Title"]. user id: @Model.UserId
-
在
Controller
:
一个。 在开头定义以下内容:
private readonly IViewRenderService _viewRenderService; public RenderController(IViewRenderService viewRenderService) { _viewRenderService = viewRenderService; }
湾 使用模型调用并返回视图,如下所示:
var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel); return Content(result);
C。 FULL控制器示例可能如下:
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 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;} } }
如果像我一样你有许多需要这个的控制器,比如报告网站,重复这个代码并不是很理想,甚至注入或调用另一个服务似乎并不合适。
所以我已经制作了我自己的上述版本,但有以下不同之处:
- 模型强类型
- 查找视图时的错误检查
- 将视图呈现为部分或页面的能力
- asynchronus
- 实现为控制器扩展
-
不需要DI
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using System.IO; using System.Threading.Tasks; namespace CC.Web.Helpers { public static class ControllerExtensions { public static async Task
RenderViewAsync (this Controller controller, string viewName, TModel model, bool partial = false) { if (string.IsNullOrEmpty(viewName)) { viewName = controller.ControllerContext.ActionDescriptor.ActionName; } controller.ViewData.Model = model; using (var writer = new StringWriter()) { IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine; ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial); if (viewResult.Success == false) { return $"A view with the name {viewName} could not be found"; } ViewContext viewContext = new ViewContext( controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, writer, new HtmlHelperOptions() ); await viewResult.View.RenderAsync(viewContext); return writer.GetStringBuilder().ToString(); } } } }
然后执行:
viewHtml = await this.RenderViewAsync("Report", model);
或者这对于PartialView:
partialViewHtml = await this.RenderViewAsync("Report", model, true);
上面的答案很好,但需要调整以使任何标记助手工作(我们需要使用实际的http上下文)。 此外,您还需要在视图中显式设置布局以获取呈现的布局。
public class ViewRenderService : IViewRenderService { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; private readonly IHostingEnvironment _env; private readonly HttpContext _http; public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext; } public async Task RenderToStringAsync(string viewName, object model) { var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor()); using (var sw = new StringWriter()) { var viewResult = _razorViewEngine.FindView(actionContext, viewName, false); //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder 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(_http, _tempDataProvider), sw, new HtmlHelperOptions()); viewContext.RouteData = _http.GetRouteData(); await viewResult.View.RenderAsync(viewContext); return sw.ToString(); } } }
下面的链接解决了几乎相同的问题:
MVC 6 Controller中的ControllerContext和ViewEngines属性在哪里?
在Hasan A Yousef的回答中,我必须进行与上面链接相同的更改,以使其适用于我:
using Microsoft.AspNetCore.Hosting; 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; using System.Threading.Tasks; public class ViewRenderService : IViewRenderService { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; private readonly IHostingEnvironment _env; public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; } public async Task 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); var viewResult = _razorViewEngine.GetView(_env.WebRootPath, 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(); } }
微软有一篇关于控制器测试的优秀文章,请访问https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing
返回ViewResult后,您可以获取字符串内容
var strResult = ViewResult.Content