0

tl;dr: My .NET Core 3.1 console application crashes with a FileNotFoundException because a (referenced?) assembly is present in version A, but required in version B. What to do?


I am trying to get a console application to run that is now built for .NET Core 3.1, but that used to be a .NET Framework 4.8 project before it was converted.

The console application crashes with a System.IO.FileNotFoundException, saying that the assembly Microsoft.Extensions.FileProviders.Physical in version 3.1.0.0 cannot befound. Now, I can confirm it's not there - in the directory where the .exe file of my console application resides, there is a file named Microsoft.Extensions.FileProviders.Physical.dll, but its assembly version is 3.1.6.0.

The console application and its dependencies are a part of a bigger project in said folder, with a total of over 1,200 DLLs.

In .NET Framework, I'd have used a binding redirect to use the present version 3.1.6.0 of the indicated assembly. In .NET Core, though, I understand these binding redirects are not a thing anymore. Thus, I'm not sure how to proceed, or how to even find out why the runtime thinks it needs to load Microsoft.Extensions.FileProviders.Physical.dll.

I may have found a partial solution that loads the version-mismatched assembly nonetheless (see observation (6) below), but then, I'm still getting a FileNotFoundException, this time for Microsoft.AspNetCore.Mvc.Abstractions.

Some observations and attempts to solve this:

  • (1) None of the > 1,200 .csproj files contains the string "Physical".

  • (2) More than 400 of the .deps.json files mention "Microsoft.Extensions.FileProviders.Physical.dll", all of them referring to version 3.1.0.0.

  • (3) All of the respective DLLs are loaded in an ASP.NET Core application where the version mismatch appears to cause no issues.

  • (4) The .deps.json file of my console application itself does not mention "Microsoft.Extensions.FileProviders.Physical.dll".

  • (5) Putting the right version of the file (3.1.0.0) into the directory where the .exe file resides and from where the .exe file is also executed does not change anything. The FileNotFoundException still occurs, still complaining about an absence of "Microsoft.Extensions.FileProviders.Physical.dll", version 3.1.0.0.

  • (6) Based upon the information on assembly resolution in .NET Core provided in a CodeProject article, I have attempted to force loading of the assemblies from the same directory myself (preliminary code, relying on the working directory):

    AssemblyLoadContext.Default.Resolving += (context, name) =>
    {
      var dllPath = System.IO.Path.Combine(Environment.CurrentDirectory, name.Name + ".dll");
    
      if (File.Exists(dllPath))
      {
        return AssemblyLoadContext.Default.LoadFromAssemblyPath(dllPath);
      }
    
      return null;
    };
    

    This appears to help to some extent! Now, the "Microsoft.Extensions.FileProviders.Physical.dll" assembly, and plenty (more than 250) of others, can be loaded. But this fails once "Microsoft.AspNetCore.Mvc.Abstractions", 3.1.0.0, needs to be loaded, which is not actually anywhere around the .exe file. Apparently, it must be loaded from somewhere else (?)

  • (7) While the above appears to provide a partial solution concerning the version mismatch, our entire source code contains no other occurrence of "AssemblyLoadContext". Therefore, the ASP.NET Core application apparently avoids the version mismatch issue using some other mechanism.

  • (8) Building my console application with build output set to Diagnostic1 confirms the suspected behaviour for the "Microsoft.Extensions.FileProviders.Physical.dll" file (shortened excerpt of the output):

    Dependency "Microsoft.Extensions.FileProviders.Physical, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60".
      Could not resolve this reference. Could not locate the assembly "Microsoft.Extensions.FileProviders.Physical, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
          For SearchPath "C:\(...)".
          Considered "C:\(...)\Microsoft.Extensions.FileProviders.Physical.winmd", but it didn't exist.
          Considered "C:\(...)\Microsoft.Extensions.FileProviders.Physical.dll",
              but its name "Microsoft.Extensions.FileProviders.Physical, Version=3.1.6.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"
              didn't match the expected name "Microsoft.Extensions.FileProviders.Physical, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60".
          Considered "C:\(...)\Microsoft.Extensions.FileProviders.Physical.exe", but it didn't exist.
      Required by "(A)".
      Required by "(B)".
      Required by "(C)".
    

    In there, (A), (B), and (C) are assemblies of our own project. But as far as I can see, neither of their .csproj files mentions the text "Physical", so I do not understand why the DLL is allegedly being required by them.

  • (9) For the "Microsoft.AspNetCore.Mvc.Abstractions" assembly, diagnostic output says:

    Dependency "Microsoft.AspNetCore.Mvc.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60".
      Could not resolve this reference. Could not locate the assembly "Microsoft.AspNetCore.Mvc.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
          For SearchPath "C:\(...)".
          Considered "C:\(...)\Microsoft.AspNetCore.Mvc.Abstractions.winmd", but it didn't exist.
          Considered "C:\(...)\Microsoft.AspNetCore.Mvc.Abstractions.dll", but it didn't exist.
          Considered "C:\(...)\Microsoft.AspNetCore.Mvc.Abstractions.exe", but it didn't exist.
          Considered "C:\(...)\Microsoft.AspNetCore.Mvc.Abstractions.winmd", but it didn't exist.
          Considered "C:\(...)\Microsoft.AspNetCore.Mvc.Abstractions.dll", but it didn't exist.
          Considered "C:\(...)\Microsoft.AspNetCore.Mvc.Abstractions.exe", but it didn't exist.
      Required by "(B)".
    

    Once again, (B) is an assembly (same as the (B) in (8)) of our own, but looking into the .csproj file does not reveal a single occurrence of "Mvc.Abstractions".


I have found a couple of questions that appeared to provide solutions, but none of them worked for me:


How can I make the runtime load version of 3.1.6.0 of the indicated assembly rather than the requested version 3.1.0.0? Alternatively, how do I find out how the runtime does it when running the ASP.NET Core application?


1: in VS2019: Tools -> Options -> Projects and Solutions -> Build And Run -> MSBuild project build output verbosity -> Diagnostic

O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
  • Have you tried explicitly installing required version of [`Microsoft.Extensions.FileProviders.Physical` nuget](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Physical/)? – Guru Stron Apr 20 '21 at 21:47
  • @GuruStron: As mentioned in the question, I don't think I should attempt to replace the DLL file. More than 400 of our assemblies mention it in their `.deps.json` files and I do not want to risk breaking anything in those. If I cannot find any other ways, though, I will try that locally tomorrow just to check whether I at least arrive at another outcome in the console application. – O. R. Mapper Apr 20 '21 at 21:54
  • Which version of Core 3.1 are you using? See : https://dotnet.microsoft.com/download/dotnet/3.1 – jdweng Apr 20 '21 at 21:55
  • @jdweng: There appears to be [no good way to obtain the currently running .NET Core version](https://weblog.west-wind.com/posts/2018/Apr/12/Getting-the-NET-Core-Runtime-Version-in-a-Running-Application), but the latest 3.1.* version of .NET Core on my machine is 3.1.14. – O. R. Mapper Apr 20 '21 at 22:02
  • You have to make sure all the pieces of your project is built with same version. Even then there may be bugs in the library. The left column of my link is the versions you should use when building app. The right column is the runtime library that you use when you deploy on a machine after building. – jdweng Apr 21 '21 at 01:23
  • @jdweng: On my machine, I have .NET Core SDK 3.1.408 installed. But you're saying it can be problematic if some parts of our team are using that version, while other parts of the team are using version 3.1.114? We may be able to mandate a certain SDK version for our own developers, but how do we ensure the very same SDK version has been used for building 3rd party binaries? – O. R. Mapper Apr 21 '21 at 05:09
  • @GuruStron: Curiously, putting exactly the referenced DLL file ( `Microsoft.Extensions.FileProviders.Physical, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60` ) into the same directory where the console application `.exe` file resides, and from where it is launched, does not change anything. That is, the `FileNotFoundException` still occurs, still complaining about an inability to find version 3.1.0.0 of that file. – O. R. Mapper Apr 21 '21 at 05:57
  • Can you create a reproducer? Do you have a global.json file and if yes what are the contents? Try performing full clean up (delete bin and objs folders, for example you can use `git clean -fdx`, beware it will delete all not committed changes also) – Guru Stron Apr 21 '21 at 06:15
  • Also build the project with verbose setting on, sometimes it can give hints what's going wrong. – Guru Stron Apr 21 '21 at 06:19
  • @GuruStron: "Can you create a reproducer?" - unfortunately, I don't know how. The framework that is loaded along with the console application will dynamically attempt to load all of the > 1,200 assemblies (for dependency injection). If I *knew* the dependency chain that leads up to the files in question (= the subset of files relevant to the problem), I would probably be quite a bit closer to a solution in the first place. – O. R. Mapper Apr 21 '21 at 06:30
  • @GuruStron: By global JSON file, are you referring to a `.deps.json` file with the same name as my console application `.exe`? Such a file is generated, ye. It has roughly 350 lines, should I look for anything specific? – O. R. Mapper Apr 21 '21 at 06:33
  • @GuruStron: I have updated the question with additional observations from diagnostic output (as well as an attempted solution using DIY assembly reolution that appears to bring a step forward, though does not entirely remove the problem). – O. R. Mapper Apr 21 '21 at 07:01
  • @O.R.Mapper check the build output before the error - sometimes the actual issue is described there. Also I believe the dependency chain can be found in that output (also it is not an easy thing to do). Have you tried to delete bin and objs folders? Have you tried to build the erroneous project standalone? – Guru Stron Apr 21 '21 at 07:17
  • You need to have 3rd party provide a installation package with setup.exe. For a Net application to run on a remote machine either you need the same version of Net on Build and Deploy machine, or you need to install like commercial software. A lot of the Net library are wrappers with just call a Windows Dll. What setup.exe does is updates the Windows dlls so deploy machine so deploy version of dll is same as build version. – jdweng Apr 21 '21 at 07:18
  • @GuruStron: In the build output, the assemblies are mentioned in a long, long list of referenced assemblies. I haven't spotted anything noteworthy before that in the log so far. And, to be clear: Despite MSBuild mentions of missing assemblies, **I am not getting any build errors.** The errors I describe in this question entirely occur **at runtime**. Deleting `bin` and `obj` doesn't change anything; after rebuilding the console application and running it, it still behaves absolutely the same, failing to find the mentioned assemblies. What exactly do you mean by "standalone" - outside of VS? – O. R. Mapper Apr 21 '21 at 07:59
  • @jdweng: I'll look more into that, but I do wonder: If *that* were the problem, how could the full ASP.NET Core application that uses the very same assembly files work (which it does!)? – O. R. Mapper Apr 21 '21 at 08:00
  • Look at the link I provided with the different versions of Core 3.1. Read the notes above the the first two releases in the right column. The second release says "This release includes the .NET Runtime, you do not need to install it separately." The latest release says "On Windows, we recommend installing the Hosting Bundle, which includes the .NET Runtime and IIS support." – jdweng Apr 21 '21 at 09:25
  • @jdweng: Well, I *have* the hosting bundle of 3.1.14 on my machine. – O. R. Mapper Apr 21 '21 at 09:57
  • I think the Microsoft Build has bugs. Core is suppose to be a compact version of Net to run on mobile devices that has less memory. So the previous release started getting too large. So they separated out some libraries into the hosting bundle that may not be needed. It looks like some libraries were missed and not included in either the regular build the hosting build. Then you may be using a feature that should not be used at all in Core. – jdweng Apr 21 '21 at 10:12
  • @jdweng: So, if I get you correctly, you're saying that the hosting build (which is used for the ASP.NET Core web application) contains the *Microsoft.AspNetCore.Mvc.Abstractions* assembly, while the regular runtime does not? In that case, the question is what makes our assemblies require *Microsoft.AspNetCore.Mvc.Abstractions*. As outlined in observation (9), the assembly indicated by MSBuild does not actually appear to reference *Microsoft.AspNetCore.Mvc.Abstractions*. – O. R. Mapper Apr 21 '21 at 22:03
  • 1
    I can't answer that question. Ask Microsoft. Microsoft tried to come up with a kludge to solver a problem, but it create other issues like yours. – jdweng Apr 21 '21 at 23:04

0 Answers0