我正在使用 wkhtmltopdf 将 cshtml 文件转换为 PDF。在本地运行时,它可以完美运行,没有任何问题(我使用的是 Windows)。但是,当我尝试将应用程序部署到 Docker 容器时,它开始抛出管道损坏的异常。
这是我的dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
RUN apt-get update && apt-get install -y --no-install-recommends wget ca-certificates fontconfig libc6 libfreetype6 libjpeg62-turbo libpng16-16 libssl3 libstdc++6 libx11-6 libxcb1 libxext6 libxrender1 xfonts-75dpi xfonts-base zlib1g
RUN wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb
RUN dpkg -i wkhtmltox_0.12.6.1-3.bookworm_amd64.deb
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["nuget.config", "."]
COPY ["src/Application/Application.csproj", "src/Application/"]
COPY ["src/Application/Rotativa", "src/Application/Rotativa"]
COPY ["src/Services/Services.csproj", "src/Services/"]
RUN dotnet restore "./src/Application/Application.csproj"
COPY . .
WORKDIR "/src/src/Application"
RUN dotnet build "./Application.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Application.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
RUN chmod -R 755 /app/Rotativa/
ENTRYPOINT ["dotnet", "Application.dll"]
这是我的PDF生成课程
using RazorEngineCore;
using Services.Features.TransferRequest.Models.Interfaces;
using Services.Features.TransferRequest.Repositories;
using Shared.Infrastructure.Interfaces;
using Shared.Infrastructure.ManipulateFiles;
using System.Collections.Concurrent;
using System.Xml.Linq;
using Wkhtmltopdf.NetCore;
using Wkhtmltopdf.NetCore.Options;
namespace Services.Features.TransferRequest.UseCases.Services;
public class PdfGeneratorService(IRazorEngine razorEngine, IGeneratePdf generatePdf, ILoggerActionEnrichService logger, IFilesReader filesReader) : IPdfGeneratorService
{
private readonly string _namespace = $"{typeof(TransferRequestModule).Namespace}.Models.Templates";
public async Task<MemoryStream> GeneratePdfAsync<TModel>(TModel model, string fileName)
{
try
{
var template = await filesReader.ReadFileWithMemoryFirstAsync(_namespace, fileName, TypeArchives.CSHTML); ;
var html = await GenerateHtmlAsync<TModel>(model, template);
return await GeneratePdf(html);
}
catch (Exception ex)
{
logger.Add($"Problemas para gerar o pdf \n Message: {ex.Message}");
logger.Add($"StackTrace: {ex.StackTrace}");
logger.Add($"InnerException: {ex.InnerException}");
logger.Add($"Exception: {ex}");
throw;
}
}
private async Task<MemoryStream> GeneratePdf(string html)
{
generatePdf.SetConvertOptions(new ConvertOptions
{
PageMargins = new Margins(0, 0, 0, 0),
});
var pdf = await Task.Run(() => generatePdf.GetPDF(html));
var pdfStream = new MemoryStream();
await pdfStream.WriteAsync(pdf, 0, pdf.Length);
pdfStream.Position = 0;
return pdfStream;
}
private async Task<string> GenerateHtmlAsync<TModel>(TModel model, string template)
=> await (await razorEngine.CompileAsync<RazorEngineTemplateBase<TModel>>(template))
.RunAsync(instance =>
{
instance.Model = model;
});
}
问题发生在以下行:
var pdf = await Task.Run(() => generatePdf.GetPDF(html));
这是堆栈跟踪:
StackTrace: at System.IO.Pipes.PipeStream.CheckWriteOperations()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at Wkhtmltopdf.NetCore.WkhtmlDriver.Convert(String wkhtmlPath, String switches, String html)
at Wkhtmltopdf.NetCore.GeneratePdf.GetPDF(String html)
at Services.Features.TransferRequest.UseCases.Services.PdfGeneratorService.<>c__DisplayClass7_0.<GeneratePdf>b__0() in /src/src/Services/Features/TransferRequest/UseCases/Services/PdfGeneratorService.cs:line 42
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Services.Features.TransferRequest.UseCases.Services.PdfGeneratorService.GeneratePdf(String html) in /src/src/Services/Features/TransferRequest/UseCases/Services/PdfGeneratorService.cs:line 42
at Services.Features.TransferRequest.UseCases.Services.PdfGeneratorService.GeneratePdfAsync[TModel](TModel model, String fileName) in /src/src/Services/Features/TransferRequest/UseCases/Services/PdfGeneratorService.cs:line 23
有人有解决办法吗?
您可以通过以下链接参考问题原因及解决方案:“https://stackoverflow.com/a/79163054/28591255”。我还将提供一些额外的见解以进一步增强该解决方案。
我会改变:
“运行 chmod -R 755 /app/Rotativa/”
到
“RUN mkdir -p /app/Rotativa/Linux &&
mv /usr/local/bin/wkhtmltopdf /app/Rotativa/Linux/ &&
chmod 755 /app/Rotativa/Linux/wkhtmltopdf"
祝你好运!