将包含URL的Razor视图渲染到ASP.NET Core中的字符串

Ron*_*ono 4 asp.net-core-mvc

我有一个通过依赖注入使用的Emailer类来发送电子邮件,该电子邮件获取要通过电子邮件发送的视图内容.我工作的过程非常好,除非视图包含对底层URL帮助器的调用,例如使用如下的A标记:

<a asp-controller="Project" asp-action="List">Open</a>
Run Code Online (Sandbox Code Playgroud)

这是我用来将视图呈现为字符串的代码:

private string renderViewAsString<TModel>(string folder, string viewName, TModel model)
{
  var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
  var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
  var viewEngineResult = _viewEngine.FindView(actionContext, folder + "/" + viewName, false);
  var view = viewEngineResult.View;

  var viewData = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
  viewData.Model = model;

  var tempData = new TempDataDictionary(httpContext, _tempDataProvider);

  using (var output = new StringWriter())
  {
    var viewContext = new ViewContext(actionContext, view, viewData, tempData, output, new HtmlHelperOptions());        
    var task = view.RenderAsync(viewContext);
    task.Wait();

    return output.ToString();
  }
}
Run Code Online (Sandbox Code Playgroud)

_serviceProvider的类型为IServiceProvider,_viewEngine的类型为IRazorViewEngine,它们都在构造函数中注入.

如果它引用URL帮助程序,它会在task.Wait()行生成此异常:

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Run Code Online (Sandbox Code Playgroud)

以此作为调用堆栈:

at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.Collections.Generic.List`1.get_Item(Int32 index)
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.get_Router()
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(String routeName, RouteValueDictionary values)
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext)
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, String action, String controller, Object values, String protocol, String host, String fragment)
at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateActionLink(ViewContext viewContext, String linkText, String actionName, String controllerName, String protocol, String hostname, String fragment, Object routeValues, Object htmlAttributes)
at Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper.Process(TagHelperContext context, TagHelperOutput output)
at Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>d__0.MoveNext()
Run Code Online (Sandbox Code Playgroud)

如何解决这个问题而不必使用硬编码A元素或电子邮件内容?

Ron*_*ono 15

我能够让它发挥作用.调用堆栈提到没有找到路由器,所以这是提供它的问题:

首先,我在构造函数参数中将其添加为DI对象:

IHttpContextAccessor accessor
Run Code Online (Sandbox Code Playgroud)

这在构造函数中:

_context = accessor.HttpContext;
Run Code Online (Sandbox Code Playgroud)

然后我将功能更改为:

private string renderViewAsString<TModel>(string folder, string viewName, TModel model)
{
  var actionContext = new ActionContext(_context, new RouteData(), new ActionDescriptor());
  var viewEngineResult = _viewEngine.FindView(actionContext, folder + "/" + viewName, false);
  var view = viewEngineResult.View;

  var viewData = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
  viewData.Model = model;

  var tempData = new TempDataDictionary(_context, _tempDataProvider);

  using (var output = new StringWriter())
  {
    var viewContext = new ViewContext(actionContext, view, viewData, tempData, output, new HtmlHelperOptions());
    viewContext.RouteData = _context.GetRouteData();   //set route data here

    var task = view.RenderAsync(viewContext);
    task.Wait();

    return output.ToString();
  }
}
Run Code Online (Sandbox Code Playgroud)