6

I have been searching for a solution for a couple of days. None of the answers work in my case which is to reference (load?) assemblies .NET into app domain from PowerShell session.

I load references first (that are required to be referenced by the aforementioned DLL to be working [Reflection.Assembly]::LoadFile() or [Reflection.Assembly]::LoadFrom()) then I load my .NET DLL by calling Add-Type.

Unfortunately that is not working so I cannot create a few instances from that DLL. I am getting the same errors when I use DLL without references attached in a normal C# project but as soon as I reference the other assemblies and recompile it works without errors (I can confirm it is because of referenced assemblies as I checked that in LinqPad as well).

PowerShell:

[System.Reflection.Assembly]::LoadFile((Get-Item -Path ".\System.Data.SQLite.dll" ).FullName)
Add-Type -Path (Get-Item -Path ".\Connector.dll" ).FullName -ReferencedAssemblies (Get-Item -Path ".\System.Data.SQLite.dll" ).FullName -PassThru | Out-Null
$certMGT = New-Object Connector

third line of that PowerShell script throws:

New-Object : Exception calling ".ctor" with "0" argument(s): "Failed to find or load the registered .Net Framework Data Provider."
At C:\Repos\Connector\bin\Installer.ps1:306 char:20
+         $certMGT = New-Object Connector
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

PSMessageDetails      : 
Exception             : System.Management.Automation.MethodInvocationException: Exception calling ".ctor" with "0" argument(s): "Failed to find or load the registered .Net Framework
                         Data Provider." ---> System.Configuration.ConfigurationErrorsException: Failed to find or load the registered .Net Framework Data Provider.
                           at System.Data.Common.DbProviderFactories.GetFactory(DataRow providerRow)
                           at System.Data.EntityClient.EntityConnection.GetFactory(String providerString)
                           at System.Data.EntityClient.EntityConnection.ChangeConnectionString(String newConnectionString)
                           at System.Data.Objects.ObjectContext..ctor(String connectionString, String defaultContainerName)
                           at Connector.Entity.ConnectorDBEntities..ctor(String connectionString)
                           at Connector.DBManager..ctor()
                           at Connector.DAL.ConfigurationDAL..ctor()
                           at Connector.ConnectorConfig..ctor()
                           at Connector.ConnectorCertMGT..ctor()
                           --- End of inner exception stack trace ---
                           at System.Management.Automation.DotNetAdapter.AuxiliaryConstructorInvoke(MethodInformation methodInformation, Object[] arguments, Object[] originalArgumen
                        ts)
                           at System.Management.Automation.DotNetAdapter.ConstructorInvokeDotNet(Type type, ConstructorInfo[] constructors, Object[] arguments)
                           at Microsoft.PowerShell.Commands.NewObjectCommand.CallConstructor(Type type, ConstructorInfo[] constructors, Object[] args)
TargetObject          : 
CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
ErrorDetails          : 
InvocationInfo        : System.Management.Automation.InvocationInfo

LinqPad query (C# Program; references Connector.dll) - this works fine

void Main()
{
    Assembly.LoadFile(@"C:\Repos\Connector\bin\System.Data.SQLite.dll");
    Connector connector = new Connector();//this also throws exactly the same error if I do not LoadFile as in above line
}
algorytmus
  • 953
  • 2
  • 9
  • 28
  • 1
    So, what's the problem? Can't you just load the dependencies/references *before* calling `Add-Type`? – Mathias R. Jessen Nov 20 '15 at 08:56
  • Yes, I do load them ( Add-Type ) before and it seems to be loaded to a different scope so that the main DLL do not resolve the assemblies properly. I have the same code in LINQPad and it works. – algorytmus Nov 20 '15 at 09:02
  • Have you tried using `Assembly.LoadFrom`? – SOReader Nov 20 '15 at 09:16
  • Now I'm confused. Could you post a code sample ? – Mathias R. Jessen Nov 20 '15 at 09:16
  • 2
    Well... that's what I wanted to ask you for. You've said you're using `LoadFile` to load dependent assemblies. AFAIR, `LoadFrom` shall be used in such cases. Paste your code, please – SOReader Nov 20 '15 at 09:19
  • LoadFrom does not work as well. There must me something with the domain. – algorytmus Nov 24 '15 at 10:32
  • Can we see full stack trace of exception `$Error[0]|fl -Force`? Does `Connector` your own class? Can we see its source? – user4003407 Nov 24 '15 at 12:01
  • Connector class is not my class. I cannot change it. Stacktrace attached. – algorytmus Nov 24 '15 at 12:10
  • I bet this must be something with resolving assemblies. – algorytmus Nov 24 '15 at 12:14
  • If it is possible to debug, it would be good to know what exact argument is passed to this call: `System.Data.Common.DbProviderFactories.GetFactory(DataRow providerRow)`. – user4003407 Nov 24 '15 at 23:44
  • 1
    Why you don't use Add-Type for System.Data.SQLite.dll ? – bdn02 Jan 13 '16 at 13:37
  • Of course I tried that. I have a suspicion that PowerShell domain has some problems in locating or choosing native dlls (\x86\SQLite.Interop.dll \x64\SQLite.Interop.dll). When I retrive [System.Type]::GetType("System.Data.SQLite.SQLiteFactory, System.Data.SQLite") I got the error: System.IO.FileLoadException: Could not load file or assembly 'System.Data.SQLite.SQLiteFactory\, System.Data.SQLite' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047) – algorytmus Jan 14 '16 at 08:24
  • The problem probably lies in your "Connector" class code. It's the one who calls into other classes that ultimately causes that error. What are you passing in Connector.Entity.ConnectorDBEntities..ctor(String connectionString) – Simon Mourier Jan 16 '16 at 08:25
  • System.Data.SQLite is an assembly that does [quite unusual stuff](http://stackoverflow.com/a/34297759/3764814). Which version are you using? Did you try the mixed-mode one? – Lucas Trzesniewski Jan 19 '16 at 21:21

1 Answers1

0

Step 1 Compile Connector.dll - presumably you already have that done

$SQLitePath = convert-path '.\res\sqlite-netFx46-binary-bundle-x64-2015-1.0.114.0\System.Data.SQLite.dll'
add-type -path $SQLitePath

$null = new-item '.\Connector.cs' -value @'
using System;
using System.Data.SQLite;

namespace Powershell.Examples{
public class Connector : System.IDisposable {
   SQLiteConnection con;

   public Connector(){}
   
   public void connect(string Path){
      con = new SQLiteConnection();
      con.ConnectionString = "Data Source=" + Path;
      con.Open();
   }
   
   public void close(){
      if(con.State == System.Data.ConnectionState.Open)
         con.Close();
   }

   bool _disposed = false;
   public void Dispose(){
      Dispose(disposing: true);
      GC.SuppressFinalize(this);
   }
   protected virtual void Dispose(bool disposing){
      if(_disposed) return;
      if(disposing){
         // free managed objects here
         con.Dispose();
      }
      // freee unmanaged objects here
      
      _disposed = true;
   }
   ~Connector(){ Dispose(disposing:false); }
}}
'@
$pams = @{
   TypeDefinition = get-content '.\Connector.cs' -raw
   OutputAssembly = '.\Connector.dll'
   OutputType     = 'Library'
   ReferencedAssemblies = @($SQLitePath,'System.Data')
}
$null = add-type @pams -PassThru

Step 2 Use it in Powershell

PS C:\Working\Folder> $SQLitePath = convert-path '.\res\sqlite-netFx46-binary-bundle-x64-2015-1.0.114.0\System.Data.SQLite.dll'
PS C:\Working\Folder> add-type -Path $SQLitePath
PS C:\Working\Folder> add-type -Path (convert-path '.\Connector.dll') -ReferencedAssemblies $SQLitePath

PS C:\Working\Folder> $obj = [Powershell.Examples.Connector]::new()
PS C:\Working\Folder> $obj.connect((Convert-Path .)+'\MyData.db')
PS C:\Working\Folder> $obj.close()
PS C:\Working\Folder> $obj.Dispose()
PS C:\Working\Folder> rv obj
Gregor y
  • 1,762
  • 15
  • 22