我遵循了本教程:https ://www.freecodecamp.org/news/convert-html-to-pdf-with-azure-functions-and-wkhtmltopdf/
解决方案是 Azure C# Function App,它将 HTML 转换为 PDF 文档并将该 PDF 保存在 blob 存储中。这个特定的功能应用程序接受以下内容,我通过 Postman 在本地运行时通过请求正文:
{
"PDFFileName": "test.pdf",
"HtmlContent": "<html>\n <head><meta http-equiv=Content-Type content=\"text/html; charset=UTF-8\">\n </head>\n <body>\n <div>test</div>\n </body> \n </html>"
}
本教程使用这个库:https ://github.com/rdvojmoc/DinkToPdf
发生的事情有点难以调试。我在本地运行函数应用程序,它运行良好,并且 PDF 保存在我的 blob 存储中,没有任何问题,但是当它运行时,我确实在控制台中看到了下面的错误。
Qt: Could not initialize OLE (error 80010106)
然后当我再次运行它时(甚至删除 pdf,以确保那里没有冲突),应用程序只是挂起,直到它返回 503 或我取消请求。
跟踪代码,这是它发生故障的这一行(来自下面的代码):
var PDFByteArray = BuildPdf(Request.HtmlContent, new MarginSettings(2, 2, 2, 2));
直接在门户中发布和运行(测试 + 代码并在逻辑应用流中运行)时,我观察到相同的行为。
我拥有的应用服务计划是基本 (B1: 1)。任何解决此问题的帮助将不胜感激!
完整代码如下:
using System;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using DinkToPdf;
using IPdfConverter = DinkToPdf.Contracts.IConverter;
[assembly: FunctionsStartup(typeof(pdfCreation.Startup))]
namespace pdfCreation
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton(typeof(IPdfConverter), new SynchronizedConverter(new PdfTools()));
}
}
public class Html2Pdf
{
// Read more about converter on: https://github.com/rdvojmoc/DinkToPdf
// For our purposes we are going to use SynchronizedConverter
IPdfConverter pdfConverter = new SynchronizedConverter(new PdfTools());
// A function to convert html content to pdf based on the configuration passed as arguments
// Arguments:
// HtmlContent: the html content to be converted
// Margins: the margis around the content
// DPI: The dpi is very important when you want to print the pdf.
// Returns a byte array of the pdf which can be stored as a file
private byte[] BuildPdf(string HtmlContent, MarginSettings Margins, int? DPI = 180)
{
// Call the Convert method of SynchronizedConverter "pdfConverter"
return pdfConverter.Convert(new HtmlToPdfDocument()
{
// Set the html content
Objects =
{
new ObjectSettings
{
HtmlContent = HtmlContent
}
},
// Set the configurations
GlobalSettings = new GlobalSettings
{
PaperSize = PaperKind.A4,
DPI = DPI,
Margins = Margins
}
});
}
private string ConnectionString(ILogger log, ExecutionContext context)
{
var config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
var connString = config.GetConnectionString("MyConnectionString");
if(connString == null){log.LogInformation("Connection String is null");}
return connString;
}
// The first arugment tells that the functions can be triggerd by a POST HTTP request.
// The second argument is mainly used for logging information, warnings or errors
[FunctionName("Html2Pdf")]
[STAThread]
public async Task<string> Run([HttpTrigger(AuthorizationLevel.Function, "POST")] Html2PdfRequest Request, ILogger Log, ExecutionContext context)
{
Log.LogInformation("C# HTTP trigger function started for HTML2PDF.");
Log.LogInformation(Request.HtmlContent);
// PDFByteArray is a byte array of pdf generated from the HtmlContent
var PDFByteArray = BuildPdf(Request.HtmlContent, new MarginSettings(2, 2, 2, 2));
// The connection string of the Storage Account to which our PDF file will be uploaded
var StorageConnectionString = ConnectionString(Log, context);
// Generate an instance of CloudStorageAccount by parsing the connection string
var StorageAccount = CloudStorageAccount.Parse(StorageConnectionString);
// Create an instance of CloudBlobClient to connect to our storage account
CloudBlobClient BlobClient = StorageAccount.CreateCloudBlobClient();
// Get the instance of CloudBlobContainer which points to a container name "pdf"
// Replace your own container name
CloudBlobContainer BlobContainer = BlobClient.GetContainerReference("pdf");
// Get the instance of the CloudBlockBlob to which the PDFByteArray will be uploaded
CloudBlockBlob Blob = BlobContainer.GetBlockBlobReference(Request.PDFFileName);
Log.LogInformation("Attempting to upload " + Request.PDFFileName);
// Upload the pdf blob
await Blob.UploadFromByteArrayAsync(PDFByteArray, 0, PDFByteArray.Length);
return "Created PDF Packing Slip.";
}
}
}
和
namespace pdfCreation
{
public class Html2PdfRequest
{
// The HTML content that needs to be converted.
public string HtmlContent { get; set; }
// The name of the PDF file to be generated
public string PDFFileName { get; set; }
}
}
.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DinkToPdf" Version="1.0.8" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.16" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.16" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.13" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0-preview1-25914-04" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
<None Update="libwkhtmltox.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
<None Update="libwkhtmltox.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="libwkhtmltox.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="wwwroot\**\*">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>