.NET Framework 4.8 Windows Service Startup Exceptions
An IronPDF .NET Framework 4.8 Windows Service project throws FileNotFoundException when constructing ChromePdfRenderer, or StackOverflowException when setting the license key. The same code works correctly in a console or WinForms host.
MSBuild's facade-detection logic prevents six NuGet-supplied assemblies from being copied to the output directory: System.ValueTuple, System.Buffers, System.Threading.Tasks.Extensions, System.Text.Json, System.Text.Encodings.Web, and System.Text.Encoding.CodePages. MSBuild assumes that the in-box .NET 4.8 versions of these assemblies are equivalent to the NuGet versions, but the binding redirects in App.config require the NuGet versions. The missing files cause the exception at startup.
Solution
Option 1: Migrate to PackageReference (Recommended)
Right-click packages.config in Visual Studio and select Migrate packages.config to PackageReference. Verify that <AutoGenerateBindingRedirects> is enabled in the .csproj file, then rebuild. PackageReference's MSBuild integration does not trigger the facade-skipping behavior.
Option 2: Force facade DLL copy with an AfterBuild target
If retaining packages.config is required, add this MSBuild target to the .csproj file:
<Target Name="CopyFacadeAssemblies" AfterTargets="Build">
<ItemGroup>
<FacadeAssemblies Include="..\packages\System.Buffers.4.5.1\lib\netstandard2.0\System.Buffers.dll" />
<FacadeAssemblies Include="..\packages\System.Text.Encodings.Web.6.0.1\lib\net461\System.Text.Encodings.Web.dll" />
<FacadeAssemblies Include="..\packages\System.Text.Json.6.0.11\lib\net461\System.Text.Json.dll" />
<FacadeAssemblies Include="..\packages\System.Text.Encoding.CodePages.5.0.0\lib\net461\System.Text.Encoding.CodePages.dll" />
<FacadeAssemblies Include="..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll" />
<FacadeAssemblies Include="..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll" />
</ItemGroup>
<Copy SourceFiles="@(FacadeAssemblies)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
</Target>
<Target Name="CopyFacadeAssemblies" AfterTargets="Build">
<ItemGroup>
<FacadeAssemblies Include="..\packages\System.Buffers.4.5.1\lib\netstandard2.0\System.Buffers.dll" />
<FacadeAssemblies Include="..\packages\System.Text.Encodings.Web.6.0.1\lib\net461\System.Text.Encodings.Web.dll" />
<FacadeAssemblies Include="..\packages\System.Text.Json.6.0.11\lib\net461\System.Text.Json.dll" />
<FacadeAssemblies Include="..\packages\System.Text.Encoding.CodePages.5.0.0\lib\net461\System.Text.Encoding.CodePages.dll" />
<FacadeAssemblies Include="..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll" />
<FacadeAssemblies Include="..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll" />
</ItemGroup>
<Copy SourceFiles="@(FacadeAssemblies)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
</Target>
Adjust version numbers to match the exact versions restored in your packages directory.
Setting <Private>True</Private> (Copy Local) on facade references does not resolve the issue; MSBuild's facade detection still blocks the copy step.

