Environment:
Microsoft Visual Studio Community 2022 (64-bit)
Version 17.4.4
Microsoft .NET Framework
Version 4.8.04084Windows 10 Pro (x64)
Version: 21H2 OS Build: 19044.2486
Project Info:
Solution with two (2) projects (Debug configuration)
Project 1 (VB.NET):
- Application Type: Class Library
- Target Framework: .NET Framework 4.8
- Target CPU: x64
Project 2 (VB.NET):
- Application Type: Windows Forms Application
- Target Framework: .NET Framework 4.8
- Target CPU: x64
In my Class Library project, I have a Nuget reference to Microsoft.Extensions.Logging.Abstractions
which is required by another Nuget package, Npgsql
(v7.0.2). The Nuget package reference to Microsoft.Extensions.Logging.Abstractions
specifically identifies v7.0.0. I even have binding redirects in the library's app.config
to point references to other versions of the library to v7.0.0 as follows:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
[...]
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
</dependentAssembly>
[...]
</assemblyBinding>
</runtime>
</configuration>
However, when I try to run my code from the IDE, every time I try to create a new NpgsqlConnection
object, it throws an exception stating (note the version listed):
Could not load file or assembly 'Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
The FusionLog property of the exception reads (redacted):
=== Pre-bind state information ===
LOG: DisplayName = Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
(Fully-specified)
LOG: Appbase = file://SERVER/Programming/My Application/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : Npgsql, Version=7.0.2.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: \\SERVER\Programming\My Application\bin\Debug\My Application.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Redirect found in application configuration file: 6.0.0.0 redirected to 6.0.0.0.
LOG: Post-policy reference: Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
LOG: Attempting download of new URL file://SERVER/Programming/My Application/bin/Debug/Microsoft.Extensions.Logging.Abstractions.DLL.
LOG: Attempting download of new URL file://SERVER/Programming/My Application/bin/Debug/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.DLL.
LOG: Attempting download of new URL file://SERVER/Programming/My Application/bin/Debug/Microsoft.Extensions.Logging.Abstractions.EXE.
LOG: Attempting download of new URL file://SERVER/Programming/My Application/bin/Debug/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.EXE.
I do not have a reference to the Microsoft.Extensions.Logging.Abstractions
library in the Windows Forms Application project:
Nor are there any binding redirects in that project's App.config
file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="Project.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<userSettings>
<Project.My.MySettings>
<setting name="LastPosition" serializeAs="String">
<value>-1, -1</value>
</setting>
<setting name="LastSize" serializeAs="String">
<value>-1, -1</value>
</setting>
</Project.My.MySettings>
</userSettings>
</configuration>
According to the accepted answer to a similar question "Could not load file or assembly Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.1.0.0", I checked the My Project.exe.config
file and found a binding redirect listed there (again, please note the version):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="Project.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<userSettings>
<Project.My.MySettings>
<setting name="LastPosition" serializeAs="String">
<value>-1, -1</value>
</setting>
<setting name="LastSize" serializeAs="String">
<value>-1, -1</value>
</setting>
</Project.My.MySettings>
</userSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
I cleaned/rebuilt the project and tried again, but it still gives the same error and, when I go look at the My Project.exe.config
file, the binding redirect is still there.
So, I added the recommended XML elements to the .vbproj
file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7BBF4599-D28D-4E03-B6D6-FC40C051263B}</ProjectGuid>
<OutputType>WinExe</OutputType>
<StartupObject>Project.My.MyApplication</StartupObject>
<RootNamespace>Project</RootNamespace>
<AssemblyName>My Application</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>WindowsForms</MyType>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<!-- VERIFIED PER STACKOVERFLOW ANSWER 43996389 -->
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<!-- ADDED PER STACKOVERFLOW ANSWER 43996389 -->
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>My Application.xml</DocumentationFile>
<NoWarn>
</NoWarn>
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>My Application.xml</DocumentationFile>
<NoWarn>
</NoWarn>
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>On</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
I verified that the AutoGenerateBindingRedirects
element was already there, so I just added the GenerateBindingRedirectsOutputType
element. I tried again to run the solution, but I encountered the same exception at the same line of code.
I then also found a suggestion in another answer to the same question to Delete all bin/obj folders, so I did that, then tried again. I still get the same error and the binding redirect has once again been added to the My Project.exe.config
file.
Virtually all of the other questions I've found about referencing the wrong version of an assembly seem to involve assemblies in the same project and just point to adding the appropriate binding redirect to the app.config
(or web.config
) file.
Just to see if it would make a difference, I went ahead and copied the entire <runtime>
element group from my Class Library project's app.config
into the App.config
of my Windows Forms Application project in an effort to force the assembly binding redirect to happen as intended. Unfortunately, when I tried again in the IDE, I still got the same error.
As stated above, the specific line of code that's throwing the exception is simply trying to instantiate a new NpgsqlConnection
object (I've verified the Me.ConnectionString
property is not NULL):
PGConnection = New NpgsqlConnection(Me.ConnectionString)
This code is actually in the Class Library project (so I don't have to have a reference to Npgsql
in all of my projects that use this same library), so I would think that it should be using the assembly that that project is referencing at runtime.
The strangest part of the whole thing is that I have this exact same Class Library project referenced in another Windows Forms Application project, and it seems to be working without any error whatsoever. I don't know why Visual Studio keeps generating this application's exe.config
file with the wrong assembly reference, and I don't know how to stop it from doing it. Could someone please point me in the right direction? If you need any additional information to help diagnose or troubleshoot the issue, I'll be happy to provide all I can.
MORE TROUBLESHOOTING
I created a brand new solution starting with a new Windows Forms Application project and once again referencing the same Class Library project:
Once set up, I tried to run it and again got the same error. Just for testing, I went into the properties of the Windows Forms Application project and turned of the option for "Auto-generate binding redirects". Running the solution again throws the same exception when I try to instantiate a new NpgsqlConnection
object.
To address the comment about downgrading the assembly back to 6.0.0, I have tried that in my troubleshooting, but that only resulted in additional errors dealing with other dependencies in my library. At one point, I even tried to downgrade the Npgsql
library to a 6.x version to see if I could get it to work that way, but that just ended up with a bunch of other compiler errors (although I don't remember exactly what those were).
I guess the simplest form of my question at this time is, "How do I get the Windows Forms Application project to stop automatically trying to load the 6.0.0 version of Microsoft.Extensions.Logging.Abstractions
?" Of course, I'd like to know why it's trying in the first place so that I can prevent it from happening in the future, but I just need to get myself out of this "DLL Hell".
I considered asking the Npgsql developers about this, but the issue definitely seems to be more related to something the Visual Studio is doing as opposed to anything the library has any sort of control over. Am I missing something obvious here?
UPDATE - WORKAROUND "FIX"
So, I finally broke down and went to the NuGet pakage manager for the Windows Forms Application project and had it install the 7.0.0 version of Microsoft.Extensions.Logging.Abstractions
there (in addition to having it installed in my Class Library project). NuGet, of course, installed a few other dependencies as well (that are, again, already included in the Class Library project).
This seems to have "resolved" this specific issue in that I no longer receive the exception when I try to instantiate a new NpgsqlConnection
object. It does not, however, answer the question about why the Windows Forms Application project is automatically generating its own binding redirect for that library and totally overriding/ignoring the specific definition I've set in the Class Library project. Also, I've been actively trying to avoid adding packages/references in the Windows Forms Application project that aren't explicitly needed by that project itself - especially those that are already in the Class Library project like this one.
Additionally, after "resolving" that assembly reference issue, I also encountered another issue with opening the connection that had to do with a similar assembly problem - this time with System.Text.Json
- so I went ahead and added that reference to my Windows Forms Application project as well. Now it all seems to be running without error but, IMO, there needs to be a way to explicitly prevent the project from trying to load specific assemblies that aren't absolutely required. To that end, I'm leaving this question open for any insight.