DEV Community

IronSoftware
IronSoftware

Posted on

Fix QuestPDF DllNotFoundException: Unable to Load QuestPdfSkia

Developers deploying QuestPDF encounter "Unable to load shared library 'QuestPdfSkia'" errors, particularly on IIS, Docker, and Linux environments. The library's native SkiaSharp dependencies are not always correctly resolved at runtime, causing DllNotFoundException that blocks PDF generation. This article documents the common causes and explores deployment alternatives.

The Problem

QuestPDF uses SkiaSharp for rendering, which requires native platform-specific libraries. These libraries must be correctly deployed and accessible at runtime. When they're not found, QuestPDF throws:

System.DllNotFoundException: Unable to load shared library 'QuestPdfSkia' or one of its dependencies
Enter fullscreen mode Exit fullscreen mode

The issue occurs because:

  • Native libraries are not copied to the output directory
  • Platform-specific NuGet packages are not installed
  • Runtime environment cannot find the library path
  • IIS application pools have restricted access

Error Messages and Symptoms

Full error message:

QuestPDF.Drawing.Exceptions.InitializationException: Cannot create the PDF document using the SkiaSharp-related library.

---> System.DllNotFoundException: Unable to load shared library 'QuestPdfSkia' or one of its dependencies.
Enter fullscreen mode Exit fullscreen mode

On IIS specifically:

QuestPdfSkia.dll not found on IIS on .NET Framework
Enter fullscreen mode Exit fullscreen mode

Symptoms include:

  • Application works in Visual Studio but fails when deployed to IIS
  • Works in development but fails in Docker containers
  • Works on Windows but fails on Linux servers
  • Inconsistent behavior between environments

Who Is Affected

This issue impacts production deployments across platforms:

Hosting Environments: IIS, Azure App Service, Docker containers, Kubernetes, Linux servers.

Framework Versions: .NET Framework 4.x on IIS, .NET Core/.NET 5-8 on various platforms.

QuestPDF Versions: Multiple versions affected, including recent releases.

Evidence from the Developer Community

GitHub Issues

Issue Title Activity
#1097 QuestPdfSkia.dll not found on IIS on .NET Framework 2024
#812 Unable to load shared library 'QuestPdfSkia' or one of its dependencies 2024
#667 Docs are stuck in 1990's - need AWS or Azure example 2023-2025

Developer Reports

"QuestPdfSkia.dll not found on IIS on .NET Framework. Works fine in Visual Studio."
— Developer, GitHub Issue #1097

"Unable to load shared library 'QuestPdfSkia' or one of its dependencies when deploying to Linux container."
— Developer, GitHub Issue #812

Root Cause Analysis

Several factors contribute to the DLL not found errors:

  1. NuGet Package Resolution: The SkiaSharp.NativeAssets packages may not be correctly referenced or may not match the runtime platform

  2. Build Output: Native DLLs may not be copied to the build output directory

  3. IIS Application Pool Identity: The IIS worker process may not have permission to load native libraries

  4. PATH Environment: The library search path may not include the directory containing native DLLs

  5. Platform Mismatch: x86 vs x64 mismatch between the application and native libraries

Solution Matrix by Deployment Scenario

The following matrix provides the specific solution for each combination of hosting environment and operating system:

Scenario OS Fix NuGet Packages Required
IIS (.NET Framework) Windows x64 Set pool to 64-bit, add native packages SkiaSharp.NativeAssets.Win32
IIS (.NET Core/.NET 5+) Windows x64 Publish as self-contained Built-in
Azure App Service Linux Add Linux native packages SkiaSharp.NativeAssets.Linux.NoDependencies
Docker (Debian) Linux Install system dependencies SkiaSharp.NativeAssets.Linux.NoDependencies
Docker (Alpine) Linux Use musl-compatible packages SkiaSharp.NativeAssets.Linux.NoDependencies
AWS Lambda Linux Custom runtime layer SkiaSharp.NativeAssets.Linux.NoDependencies
Google Cloud Run Linux Include in container SkiaSharp.NativeAssets.Linux.NoDependencies
Self-hosted Linux Debian/Ubuntu Install libfontconfig SkiaSharp.NativeAssets.Linux
Self-hosted Linux CentOS/RHEL Install additional deps SkiaSharp.NativeAssets.Linux.NoDependencies

Complete .csproj Examples

For Windows IIS Deployment (.NET 8):

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <!-- Ensure 64-bit output -->
    <PlatformTarget>x64</PlatformTarget>
    <!-- Self-contained deployment includes all dependencies -->
    <SelfContained>true</SelfContained>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="QuestPDF" Version="2024.10.2" />
    <!-- Explicitly include for .NET Framework compatibility -->
    <PackageReference Include="SkiaSharp.NativeAssets.Win32" Version="2.88.7" />
    <PackageReference Include="HarfBuzzSharp.NativeAssets.Win32" Version="7.3.0" />
  </ItemGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

For Linux Container Deployment:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
    <SelfContained>false</SelfContained>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="QuestPDF" Version="2024.10.2" />
    <!-- NoDependencies variant doesn't require system libraries -->
    <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
    <PackageReference Include="HarfBuzzSharp.NativeAssets.Linux" Version="7.3.0" />
  </ItemGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

For AWS Lambda:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
    <AWSProjectType>Lambda</AWSProjectType>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="2.2.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.0" />
    <PackageReference Include="QuestPDF" Version="2024.10.2" />
    <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
    <PackageReference Include="HarfBuzzSharp.NativeAssets.Linux" Version="7.3.0" />
  </ItemGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

IIS Configuration Guide

Step 1: Configure Application Pool

In IIS Manager:

  1. Select Application Pools in the left panel
  2. Right-click your application pool and select "Advanced Settings"
  3. Under "General" section, set Enable 32-Bit Applications to False
  4. Under "Process Model", ensure Identity has sufficient permissions

Step 2: Verify Platform Target

Your application's platform target must match the application pool settings:

<!-- In .csproj -->
<PropertyGroup>
  <PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
Enter fullscreen mode Exit fullscreen mode

Step 3: Check Native DLL Location

After publishing, verify the native DLLs are in the correct location:

/YourPublishedApp/
├── runtimes/
│   └── win-x64/
│       └── native/
│           ├── libSkiaSharp.dll
│           └── libHarfBuzzSharp.dll
├── YourApp.dll
└── web.config
Enter fullscreen mode Exit fullscreen mode

If the runtimes folder is missing, your NuGet packages are not correctly configured.

Attempted Workarounds

Workaround 1: Add Explicit NativeAssets References

Approach: Explicitly reference the native asset packages for your target platform.

<PackageReference Include="SkiaSharp.NativeAssets.Win32" Version="2.88.7" />
<PackageReference Include="HarfBuzzSharp.NativeAssets.Win32" Version="7.3.0" />
Enter fullscreen mode Exit fullscreen mode

For Linux:

<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Package versions must match exactly
  • Different packages needed for different platforms
  • May still fail in some configurations

Workaround 2: Copy Native DLLs Manually

Approach: Post-build copy native DLLs to output directory.

<Target Name="CopyNativeDlls" AfterTargets="Build">
  <Copy SourceFiles="$(NuGetPackageRoot)skiasharp.nativeassets.win32\2.88.7\runtimes\win-x64\native\*.dll"
        DestinationFolder="$(OutDir)" />
</Target>
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Fragile and version-dependent
  • Must update when package versions change
  • Different paths for different platforms

Workaround 3: Configure IIS Application Pool

Approach: Ensure correct bitness and identity for IIS application pool.

# Set 64-bit mode
Set-ItemProperty IIS:\AppPools\YourAppPool -Name enable32BitAppOnWin64 -Value $false
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Only addresses IIS-specific issues
  • May conflict with other application requirements
  • Requires infrastructure changes

Workaround 4: AWS Lambda Custom Layer

Approach: Create a Lambda layer with the required native libraries.

# Create layer structure
mkdir -p layer/lib
cd layer

# Copy required libraries from a working Linux environment
cp /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 lib/
cp /usr/lib/x86_64-linux-gnu/libfreetype.so.6 lib/

# Package the layer
zip -r questpdf-layer.zip lib/

# Upload to AWS Lambda as a layer
aws lambda publish-layer-version \
    --layer-name questpdf-dependencies \
    --zip-file fileb://questpdf-layer.zip \
    --compatible-runtimes dotnet8
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Requires deep knowledge of Linux shared library dependencies
  • Layer must be maintained separately from application
  • Cold start times increase
  • Lambda timeout limits may affect complex PDFs

Workaround 5: Google Cloud Run Configuration

Approach: Build a container with all dependencies for Cloud Run.

# Dockerfile for Google Cloud Run
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app

# Install dependencies
RUN apt-get update && apt-get install -y \
    libfontconfig1 \
    libfreetype6 \
    && rm -rf /var/lib/apt/lists/*

COPY --from=build /app/publish .

# Cloud Run specific
ENV PORT=8080
EXPOSE 8080

ENTRYPOINT ["dotnet", "YourApp.dll"]
Enter fullscreen mode Exit fullscreen mode

Deploy with:

gcloud run deploy pdf-generator \
    --image gcr.io/your-project/pdf-generator \
    --platform managed \
    --memory 2Gi \
    --timeout 300
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Increased build complexity
  • Container size increases
  • Must track dependency updates

Workaround 6: Self-Hosted Linux Server Setup

Approach: Install required system libraries on the server.

For Debian/Ubuntu:

sudo apt-get update
sudo apt-get install -y \
    libfontconfig1 \
    libfreetype6 \
    libpng16-16 \
    libjpeg62-turbo
Enter fullscreen mode Exit fullscreen mode

For CentOS/RHEL:

sudo yum install -y \
    fontconfig \
    freetype \
    libpng \
    libjpeg-turbo
Enter fullscreen mode Exit fullscreen mode

Limitations:

  • Requires server access and sudo permissions
  • Must be repeated on each server
  • May conflict with other applications
  • Package names vary by distribution

A Different Approach: IronPDF

IronPDF bundles all native dependencies in the NuGet package, eliminating DLL-not-found errors.

Why IronPDF Avoids DLL Loading Issues

IronPDF's packaging strategy differs fundamentally:

  1. All-In-One Package: Native libraries are included in the main NuGet package
  2. Automatic Extraction: Libraries are extracted to the correct location at runtime
  3. Platform Detection: The correct binaries are loaded based on runtime detection
  4. No Manual Configuration: Works without additional package references or build steps

Code Example

using IronPdf;

public class ReportService
{
    public byte[] GenerateReport(ReportData data)
    {
        // Works on IIS, Docker, Linux, Windows without DLL configuration
        var renderer = new ChromePdfRenderer();

        string html = BuildReportHtml(data);

        using var pdf = renderer.RenderHtmlAsPdf(html);
        return pdf.BinaryData;
    }

    private string BuildReportHtml(ReportData data)
    {
        return $@"
<!DOCTYPE html>
<html>
<head>
    <style>
        body {{ font-family: Arial, sans-serif; margin: 40px; }}
        table {{ width: 100%; border-collapse: collapse; }}
        th, td {{ padding: 10px; border: 1px solid #ddd; }}
        th {{ background-color: #4a90a4; color: white; }}
    </style>
</head>
<body>
    <h1>{data.Title}</h1>
    <table>
        <thead>
            <tr>
                {string.Join("", data.Headers.Select(h => $"<th>{h}</th>"))}
            </tr>
        </thead>
        <tbody>
            {GenerateRows(data.Rows)}
        </tbody>
    </table>
</body>
</html>";
    }

    private string GenerateRows(IEnumerable<string[]> rows)
    {
        return string.Join("", rows.Select(row =>
            $"<tr>{string.Join("", row.Select(cell => $"<td>{cell}</td>"))}</tr>"));
    }
}
Enter fullscreen mode Exit fullscreen mode

Deployment (no special configuration):

<!-- Just reference IronPdf - no platform-specific packages needed -->
<PackageReference Include="IronPdf" Version="*" />
Enter fullscreen mode Exit fullscreen mode

Key points:

  • Single NuGet reference for all platforms
  • No manual DLL copying required
  • Works on IIS without application pool configuration
  • Same code deploys to Docker, Linux, Windows

API Reference

For deployment documentation:

Migration Considerations

Licensing

  • IronPDF is commercial software with perpetual licensing
  • Free trial available for evaluation
  • Licensing information

API Differences

  • QuestPDF: Fluent C# API
  • IronPDF: HTML/CSS-based rendering
  • Fundamentally different document creation approaches

What You Gain

  • Single package with all dependencies included
  • Works across platforms without configuration
  • No DLL loading errors in production

What to Consider

  • Different document generation paradigm
  • HTML templates instead of fluent API
  • Commercial licensing required

Conclusion

QuestPDF's DllNotFoundException errors stem from the complexity of SkiaSharp's native dependencies across different platforms and deployment scenarios. The workarounds involve manual package references, build configuration, and infrastructure changes. For simpler deployments, libraries that bundle all dependencies in a single package eliminate this category of production issues.


Written by Jacob Mellor, CTO at Iron Software.


References

  1. QuestPDF GitHub Issue #1097{:rel="nofollow"} - QuestPdfSkia.dll not found on IIS
  2. QuestPDF GitHub Issue #812{:rel="nofollow"} - Unable to load shared library

For the latest IronPDF documentation and tutorials, visit ironpdf.com.

Top comments (0)