You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6 Web API中Razor类库生成PDF时图片无法显示的问题排查

问题分析与解决方案

首先,咱们得揪出核心问题:你现在用模拟的ActionContext渲染RCL里的cshtml时,两个关键环节掉链子了:一是模拟的上下文没法正确解析RCL嵌入式静态文件的路径,二是DinkToPdf依赖的wkhtmltopdf是无头浏览器,它没法识别Web API内部的相对路径或未暴露的嵌入式资源。

先说说你已尝试方案的问题点

  1. Url.Content()失效:你用DefaultHttpContext生成的ActionContext没有真实的请求上下文(比如Scheme、Host、正确的文件提供器关联),所以Url.Content()没法生成能被外部访问的有效路径。
  2. 静态文件配置可能错配:你的EditorRCLConfigureOptions里用了GetType().Assembly,如果图片是放在RCL项目里的,这个Assembly指向的是WebApi项目,不是RCL的,所以ManifestEmbeddedFileProvider根本找不到RCL里的静态文件。

针对性解决方案,按优先级排序

方案1:把图片转成Base64嵌入HTML(最稳妥,无外部依赖)

既然图片是RCL里的嵌入式资源,直接读取它的字节码转成Base64,塞进ViewModel里,这样生成的HTML自带图片内容,完全不用依赖外部路径。

步骤:

  1. 在存放图片的RCL项目的.csproj里确保配置正确:
<ItemGroup>
  <EmbeddedResource Include="StaticFiles\images\logo.jpg" />
  <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</ItemGroup>
  1. 在你的PDF逻辑项目里,写个方法读取嵌入式资源转Base64:
public string GetLogoBase64()
{
    var assembly = typeof(YourRclProjectNamespace.SomeClass).Assembly; // 指向RCL的程序集
    using var stream = assembly.GetManifestResourceStream("YourRclProjectNamespace.StaticFiles.images.logo.jpg");
    if (stream == null) throw new FileNotFoundException("Logo not found in embedded resources");
    
    byte[] bytes = new byte[stream.Length];
    stream.Read(bytes, 0, bytes.Length);
    return Convert.ToBase64String(bytes);
}
  1. 在InvoiceViewModel里加个LogoBase64属性,赋值后传给cshtml:
<img src="data:image/jpeg;base64,@Model.LogoBase64" class="img" alt="Company Logo"/>

方案2:修复静态文件配置+生成绝对URL(适合需要复用静态资源的场景)

如果不想嵌Base64,得让wkhtmltopdf能通过HTTP访问到图片:

  1. 修正EditorRCLConfigureOptions的程序集指向:
// 替换成RCL项目的程序集,比如引用RCL后,用RCL里某个类的Assembly
var filesProvider = new ManifestEmbeddedFileProvider(typeof(RclStaticFilesMarker).Assembly, "StaticFiles");
  1. 渲染HTML时,给模拟的HttpContext补全请求上下文信息,让Url.Content()生成绝对URL:
private ActionContext GetActionContext()
{
    var httpContext = new DefaultHttpContext
    {
        RequestServices = _serviceProvider
    };
    // 补上真实的Scheme和Host,比如从配置读取,或者开发环境硬编码
    httpContext.Request.Scheme = "https";
    httpContext.Request.Host = new HostString("localhost:5001"); // 你的WebApi地址
    return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
  1. 然后在cshtml里用Url.Content()生成绝对路径:
<img src="@Url.Content("~/StaticFiles/images/logo.jpg")" class="img" alt="Company Logo"/>

这样生成的HTML里会有完整的https://localhost:5001/StaticFiles/images/logo.jpg,wkhtmltopdf就能正常拉取图片了。

方案3:使用本地绝对路径(适合开发/测试,或部署时能固定文件位置)

你已经试过这个方法可行,那可以把图片复制到WebApi的wwwroot目录,然后在cshtml里用:

<img src="@Url.Content("~/images/logo.jpg")" class="img" alt="Company Logo"/>

或者通过配置项读取部署时的图片路径,传给ViewModel动态生成src。

总结

优先用方案1,完全避免路径依赖问题;如果需要复用静态资源,就用方案2修复配置和上下文;方案3适合快速测试。

内容的提问来源于stack exchange,提问作者DaanJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 16:59:11