参数 'ViewName' 与渲染视图中的任何可用视图都不匹配字符串 asp.net 核心

Parameter 'ViewName' does not match any available view in render view to string asp.net core

我正在使用 .net6,我想将视图呈现为字符串以发送电子邮件,但我收到错误消息:

视图寻址正确,但无法渲染。

控制器(项目。Web/Controllers/AccountController.cs):

          string body = _viewRender.RenderToStringAsync("~/Views/Account/Email/EmailBody.cshtml", user);
          SendEmail.Send(register.Email, "Activation email", body);

将视图呈现为字符串 class(Project.Core/Convertors/RenderViewToString.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 PotLearn.Core.Convertors
{
    public interface IViewRenderService
    {
        string RenderToStringAsync(string viewName, object model);
    }
    public class RenderViewToString : IViewRenderService
    {
        private readonly IRazorViewEngine _razorViewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public RenderViewToString(IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _razorViewEngine = razorViewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public  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()
                );

                 viewResult.View.RenderAsync(viewContext);
                return sw.ToString();
            }
        }
    }
}

查看(项目。Web/Views/Account/Email/EmailBody.cshtml):

@model PotLearn.DataLayer.Entities.User.User


<p>@Model.UserName hello!</p>

谢谢

您收到此错误是因为您使用的是 custom/dummy ActionContext 与实际执行的方法无关,并结合了视图引擎 FindView 方法。

FindView 方法需要来自执行上下文的信息。
来自 documentation

Finds the view with the given viewName using view locations and information from the context.


由于您传递的是绝对路径,因此您可以通过调用视图引擎 GetView 方法来解决问题,该方法不依赖于执行上下文。

var viewResult = _razorViewEngine.GetView(null, pathToView, false);

查看下面的完整代码。


您的代码还有第二个问题 - 虽然与查找视图无关;
未等待以下呼叫。

viewResult.View.RenderAsync(viewContext);

要解决,您需要 await 那个,这需要您的方法签名更改为 return Task<string>.

public interface IViewRenderService
{
    Task<string> RenderToStringAsync(string pathToView, object model);
}

渲染视图的调用看起来像

string body = await _viewRender.RenderToStringAsync("~/Views/Account/Email/EmailBody.cshtml", user);

渲染方法的完整代码

public async Task<string> RenderToStringAsync(string pathToView, 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.GetView(null, pathToView, false);
        if (viewResult.View == null)
        {
            throw new ArgumentNullException($"{pathToView} 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();
    }
}