SqlClient: Null reference on Microsoft.Data.SqlClient.SqlClientFactory.Instance if loaded using Assembly.LoadFrom() in AppDomain.CurrentDomain.AssemblyResolve delegate

when Microsoft.Data.SqlClient.dll (System.Data.SqlClient.dll the same) is resolved by following delegate dynamically at runtime, the Microsoft.Data.SqlClient.SqlClientFactory.Instance would be null.

While if not (such as reference as static nuget package at compile time), it works well.

AppDomain.CurrentDomain.AssemblyResolve += (sender, asm) =>
           {
               Assembly assembly = null;

               //if (asm.Name.StartsWith("System.Data.SqlClient")) return Assembly.Load(asm.Name);

               var dirs = Directory.GetDirectories(AppDomain.CurrentDomain.BaseDirectory).Concat(Directory.GetDirectories(Directory.GetCurrentDirectory())).ToList();
               dirs.Insert(0, Directory.GetCurrentDirectory());
               dirs.Insert(0, AppDomain.CurrentDomain.BaseDirectory);

               foreach (var p in dirs.Select(i => Path.Combine(i, new AssemblyName(asm.Name).Name + ".dll")).Where(i => File.Exists(i)))
                   try
                   {
                       assembly = Assembly.LoadFrom(p);
                       if (asm.Name.StartsWith("Microsoft.Data.SqlClient"))
                       {
                           var type = assembly.GetType(new AssemblyName(asm.Name).Name + ".SqlClientFactory");
                           System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);
                           var ci = type.GetProperties(BindingFlags.Static | BindingFlags.Public);                            // <-- ci == null here
                       }

                       break;
                   }
                   catch (Exception ex) { LogMan.Debug(ex.Message, ex); }

               return assembly;
           };

I found the problem only occurs if use own AssemblyResolver!! with the exception:

System.InvalidOperationException:“The requested .NET Data Provider’s implementation does not have an Instance field of a System.Data.Common.DbProviderFactory derived type.”

In my project, i met the issue when System.Data.SqlClient is only loaded by my own plugin assembly loader, where the AppDomain.CurrentDomain.AssemblyResolve delegate is used to resolve missing assemblies .

If i reference Microsoft.Data.SqlClient directly as nuget package in my entry assembly, it works well. but not possible as in plugin. I think there’s something wrong in underlying assembly resolving process, when use own assembly resolver.

I replaced Microsoft.Data.SqlClient with System.Data.SqlClient, it’s the same issue.

related issue: https://github.com/dotnet/SqlClient/issues/1424 , this guy seemed to have used his own AssemblyResolver.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 18 (8 by maintainers)

Most upvoted comments

Thanks @xiaoyuvax for that gist, though I have one question, it’s clear that for managed dependencies you are resolving using AssemblyResolve() but how you are triggering the loading of UN-managed native dependency because AssemblyResolve() is not triggering for SNI.dll files.

it doesn’t matter if it is triggered, nor even when it is loaded, it will work as long as the sni.dll is loaded anytime before the Microsoft.Data.SqlClient.dll is loaded, and it will be kept in memory waiting to serve. so do the unmanged loading anytime before loading the managed assembly is just ok.

according to my understanding, NativeLibrary.SetDllImportResolver() may affect loading of other dlls, i don’t think it’s proper. load ur specific dll and make it work , that’s just neatly enough.

We’ve explained it multiple times. MDS doesn’t load any of the assemblies itself. Nor does it call P/Invoke directly for the native SNI DLL. It uses DllImport attributes on extern references and lets .NET choose the DLL. Your custom assembly loader is the problem.