代码之家  ›  专栏  ›  技术社区  ›  Tachyon

未找到部分视图

  •  1
  • Tachyon  · 技术社区  · 7 年前

    我现在正忙于构建一个电子邮件引擎,它使用Razor模板系统来提供电子邮件模板。我贴了这个 question 昨天我解决了。

    现在的问题似乎是,当我在视图中包含一个部分视图时,它就找不到了。我试图将部分视图包含在视图中,如下所示:

    @await Html.PartialAsync("~/Views/Shared/EmailButton.cshtml", new EmailButtonViewModel("Confirm Account", "https://google.com"))
    

    我试过把 ~ 在没有效果的情况下,我使用反射获取到部分视图的整个路径,并将其传递到 PartialAsync 那也不管用。我已尝试将整个路径添加到 startup.cs 具体如下:

    services.Configure<RazorViewEngineOptions>(o =>
    {
        var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        o.ViewLocationFormats.Add("~/Views/Shared/{0}" + RazorViewEngine.ViewExtension);
    });
    

    ~ dir 指定文件夹中也不起作用的整个位置。我的电子邮件模板在.NET核心类库中,它们拥有 Build Action 设置为 Content Copy to output directory Copy always

    我不确定还有什么要尝试。

    Error


    文件夹结构

    类库的文件夹结构如下: Folder structure


    代码

    启动.cs 如下所示(为了简洁起见,去掉了不必要的部分):

    services.AddScoped<IRazorViewToStringRenderer, RazorViewToStringRenderer>();
    services.AddScoped<Email>();
    
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.Configure<RazorViewEngineOptions>(o =>
    {
        var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        o.ViewLocationFormats.Add("~/Views/Shared/{0}" + RazorViewEngine.ViewExtension);
    });
    

    呈现视图并将其转换为字符串的代码如下所示:

    await _razorViewToStringRenderer.RenderViewToStringAsync("Views/Emails/NewOrder/NewOrder.cshtml", newOrderModel);
    

    RenderViewToStringAsync 具体如下:

    public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
    {
        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();
        }
    }
    

    FindView 代码为

    private IView FindView(ActionContext actionContext, string viewName)
    {
        var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        var getViewResult = _viewEngine.GetView(executingFilePath: dir, 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);
    }
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   Dimitri    7 年前

    你试过了吗:

    @await Html.PartialAsync("EmailButton", new EmailButtonViewModel("Confirm Account", "https://google.com"))
    
    推荐文章