Has*_*sef 53 c# asp.net razor .net-core asp.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();
}
}
Run Code Online (Sandbox Code Playgroud)
假设能够使用以下控制器从控制器调用:
var strView = this.RenderViewToString("YourViewName", yourModel);
Run Code Online (Sandbox Code Playgroud)
当我尝试将上述内容运行到.NET Core时,我遇到了很多编译错误.
我试图将其转换为使用.NET Core,但失败了,任何人都可以帮助提及所需的using ..和所需"dependencies": {
"Microsoft.AspNetCore.Mvc": "1.1.0",
...
},的project.json.
注意
我需要解决方案来将视图转换为string.NET Core,无论相同的代码是否被转换,或者其他方式可以做到.
Red*_*Red 69
如果像我一样,你有许多需要这个的控制器,比如在报告网站中,重复这段代码并不是很理想,甚至注入或调用另一个服务似乎并不合适.
所以我已经制作了我自己的上述版本,但有以下不同之处:
不需要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<string> RenderViewAsync<TModel>(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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)然后执行:
viewHtml = await this.RenderViewAsync("Report", model);
Run Code Online (Sandbox Code Playgroud)
或者这对于PartialView:
partialViewHtml = await this.RenderViewAsync("Report", model, true);
Run Code Online (Sandbox Code Playgroud)
Has*_*sef 42
感谢Paris Polyzos和他的文章.
我在这里重新发布他的代码,以防原始帖子因任何原因被删除.
Service在文件中创建viewToString.cs如下代码:
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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将服务添加到Startup.cs文件中,如下所示:
using WebApplication.Services;
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IViewRenderService, ViewRenderService>();
}
Run Code Online (Sandbox Code Playgroud)添加"preserveCompilationContext": true到buildOptions中project.json,所以文件看起来像:
{
"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"
}
}
}
Run Code Online (Sandbox Code Playgroud)
定义你model,例如:
public class InviteViewModel {
public string UserId {get; set;}
public string UserName {get; set;}
public string ReferralCode {get; set;}
public int Credits {get; set;}
}
Run Code Online (Sandbox Code Playgroud)创建你Invite.cshtml的例子:
@{
ViewData["Title"] = "Contact";
}
@ViewData["Title"].
user id: @Model.UserId
Run Code Online (Sandbox Code Playgroud)在Controller:
一个.在开头定义以下内容:
private readonly IViewRenderService _viewRenderService;
public RenderController(IViewRenderService viewRenderService)
{
_viewRenderService = viewRenderService;
}
Run Code Online (Sandbox Code Playgroud)
湾 使用模型调用并返回视图,如下所示:
var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
return Content(result);
Run Code Online (Sandbox Code Playgroud)
C.完整的控制器示例,可能是:
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;}
}
}
Run Code Online (Sandbox Code Playgroud)
HMZ*_*HMZ 23
ASP.NET 核心 3.1
我知道这里有很多好的答案,我想我也分享我的:
这是从 GitHub 上的 asp.net core 的源代码中提取的,我通常使用它来使用 Razor 呈现 HTML 电子邮件以及通过 Ajax 或 SignalR 返回部分视图的 HTML。
添加为瞬态服务并在控制器中注入 DI
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.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
public sealed class RazorViewToStringRenderer : IRazorViewToStringRenderer
{
private readonly IRazorViewEngine _viewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public RazorViewToStringRenderer(
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
{
//If you wish to use the route data in the generated view (e.g. use
//the Url helper to construct dynamic links)
//inject the IHttpContextAccessor then use: var actionContext = new ActionContext(_contextAccessor.HttpContext, _contextAccessor.HttpContext.GetRouteData(), new ActionDescriptor());
//instead of the line below
var actionContext = GetActionContext();
var view = FindView(actionContext, viewName);
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());
await view.RenderAsync(viewContext);
return output.ToString();
}
}
private IView FindView(ActionContext actionContext, string viewName)
{
var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
if (getViewResult.Success)
{
return getViewResult.View;
}
var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: true);
if (findViewResult.Success)
{
return findViewResult.View;
}
var searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations);
var errorMessage = string.Join(
Environment.NewLine,
new[] { $"Unable to find view '{viewName}'. The following locations were searched:" }.Concat(searchedLocations)); ;
throw new InvalidOperationException(errorMessage);
}
private ActionContext GetActionContext()
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = _serviceProvider;
return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
}
public interface IRazorViewToStringRenderer
{
Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model);
}
Run Code Online (Sandbox Code Playgroud)
Pha*_*lon 10
Red的回答使我有99%的解决方法,但是如果您的视图位于意外位置,则无法使用。这是我的解决办法。
using Microsoft.AspNetCore.Hosting;
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 Example
{
public static class ControllerExtensions
{
public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool isPartial = 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 = GetViewEngineResult(controller, viewName, isPartial, viewEngine);
if (viewResult.Success == false)
{
throw new System.Exception($"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();
}
}
private static ViewEngineResult GetViewEngineResult(Controller controller, string viewName, bool isPartial, IViewEngine viewEngine)
{
if (viewName.StartsWith("~/"))
{
var hostingEnv = controller.HttpContext.RequestServices.GetService(typeof(IHostingEnvironment)) as IHostingEnvironment;
return viewEngine.GetView(hostingEnv.WebRootPath, viewName, !isPartial);
}
else
{
return viewEngine.FindView(controller.ControllerContext, viewName, !isPartial);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这使您可以如下使用它:
var emailBody = await this.RenderViewAsync("~/My/Different/View.cshtml", myModel);
Run Code Online (Sandbox Code Playgroud)
Mah*_*san 10
这里已经发布了很多很棒的答案。基本上我遇到了类似的问题,我想从 razor (.cshtml) 页面读取电子邮件模板作为字符串,我遇到了这个问题并尝试了所有答案。我在 .NET 5 中遇到了一些问题,因此我在这里发布了稍微调整过的解决方案。谢谢。
Startup.cs文件
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<CustomViewRendererService>();
...
}
Run Code Online (Sandbox Code Playgroud)
CustomViewRendererService.cs文件
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Services
{
public class CustomViewRendererService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
public CustomViewRendererService(
IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
}
public async Task<string> RenderViewToStringAsync(ControllerContext actionContext, string viewPath, object model)
{
var viewEngineResult = _razorViewEngine.GetView(viewPath, viewPath, false);
if (viewEngineResult.View == null || (!viewEngineResult.Success))
{
throw new ArgumentNullException($"Unable to find view '{viewPath}'");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), actionContext.ModelState);
viewDictionary.Model = model;
var view = viewEngineResult.View;
var tempData = new TempDataDictionary(actionContext.HttpContext, _tempDataProvider);
using var sw = new StringWriter();
var viewContext = new ViewContext(actionContext, view, viewDictionary, tempData, sw, new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return sw.ToString();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我的控制器中
public class TestController : ControllerBase
{
private readonly CustomViewRendererService _viewService;
public TestController(CustomViewRendererService viewService)
{
_viewService = viewService;
}
public async Task<IActionResult> SendTestEmail2Async()
{
var templatePath = "~/Views/Email/Test.cshtml";
var msg = await _viewService.RenderViewToStringAsync(ControllerContext, templatePath, ("Foo", "Bar"));
return Ok(msg);
}
}
Run Code Online (Sandbox Code Playgroud)
最后Test.cshtml归档
@model (string arg1, string arg2)
<h1>Param: @Model.arg1</h1>
<h1>Param @Model.arg2</h1>
Run Code Online (Sandbox Code Playgroud)
上面的答案很好,但需要进行调整才能使任何标签助手工作(我们需要使用实际的 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<string> 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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可能迟到了,但我设法找到了一种解决方案,该解决方案无需实例化新的视图引擎( RazorViewEngine ),而是实际重用每个控制器中已有的视图引擎。此外,通过这种方法,我们还可以在键入视图名称时从IntelliSense获得帮助,这在尝试确定确切的视图路径时非常有用。
因此,使用这种方法,您的代码将如下所示:
public override async Task<IActionResult> SignUp()
{
...
// send an email notification
var emailView = View("Emails/SignupNotification"); // simply get the email view
var emailBody = await RenderToStringAsync(emailView, _serviceProvider); // render it as a string
SendEmail(emailBody);
...
return View();
}
Run Code Online (Sandbox Code Playgroud)
RenderToStringAsync本示例中使用的方法如下所示:
private static async Task<string> RenderToStringAsync(ViewResult viewResult, IServiceProvider serviceProvider)
{
if (viewResult == null) throw new ArgumentNullException(nameof(viewResult));
var httpContext = new DefaultHttpContext
{
RequestServices = serviceProvider
};
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var stream = new MemoryStream())
{
httpContext.Response.Body = stream; // inject a convenient memory stream
await viewResult.ExecuteResultAsync(actionContext); // execute view result on that stream
httpContext.Response.Body.Position = 0;
return new StreamReader(httpContext.Response.Body).ReadToEnd(); // collect the content of the stream
}
}
Run Code Online (Sandbox Code Playgroud)
如果您将该方法实现为扩展方法,则您的用法可以变成:
public override async Task<IActionResult> SignUp()
{
...
var emailBody = View("Emails/SignupNotification")
.RenderToStringAsync(_serviceProvider);
...
return View();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
28690 次 |
| 最近记录: |