Loading Assemblies from NuGet Packages

社会主义新天地 提交于 2019-11-28 23:31:11

crownedjitter's helpful answer is a good starting point, and Travis himself has provided additional pointers in comments, but let me try to summarize as of Windows PowerShell v5.1:

  • As stated, PowerShell v5+ - including PowerShell Core - comes with the PackageManagement module that is a meta package manager providing access to multiple repositories via providers; on-demand installation of this module is may be possible in v3 and v4 (this download is labeled "March 2016 Preview", and it is the most recent I could find).

    • Find-PackageProvider lists all available providers.
    • Get-PackageProvider lists installed ones.
  • It is the nuget provider that enables installation of Nuget packages via Install-Package, and there are two potential hurdles:

    • The nuget provider may not be installed.

    • It may be installed with an incorrect API URL that prevents Find-Package from returning results.

Test if the nuget provider is installed:

# If this fails, the provider isn't installed
Get-PackageProvider nuget

If it is installed: Verify that the package source URI is correct:

  • Open an elevated PowerShell session.
  • Run Get-PackageSource:
    • If you find a Nugettest source, remove it:
      • Unregister-PackageSource Nugettest
    • If the Location column for source nuget.org shows https://api.nuget.org/v3/index.json (or something other than ttps://www.nuget.org/api/v2), update it:

If it is not installed: Install the provider from scratch:

  • Open an elevated PowerShell session.
  • Run the following commands:

    Install-PackageProvider nuget
    Register-PackageSource -ProviderName nuget -name nuget.org -Location https://www.nuget.org/api/v2 -Trusted
    

After completing the above steps, discovery (e.g., Find-Package Dapper) and installation (e.g., Install-Package Dapper) of NuGet packages should succeed.

By default, Install-Package installs in the AllUsers scope, which requires elevation, but you can opt into installing in the context of the current user only with -Scope CurrentUser.


Using a downloaded NuGet package:

Note: See this suggestion on GitHub for making the use of NuGet packages in PowerShell easier by extending Add-Type, which would obviate the need for all subsequent steps, which are still needed as of PowerShell Core 6.2.0.

  • As demonstrated in the question, you need to manually load the package's assemblies into your PowerShell session with Add-Type -Path <assembly-file-path>; however, in the era of .NET Core, packages may have DLLs for different .NET environments, so you cannot always blindly load all *.dll files in the package folder:

  • In order to discover the file-system location of a downloaded package, query the .Source property of the relevant object returned by Get-Package:

    (Get-Package Dapper).Source
    
  • To see the full paths of all DLLs inside the package, run the following:

    (Get-ChildItem -Filter *.dll -Recurse (Split-Path (Get-Package Dapper).Source)).FullName
    
  • Looking at the full DLL paths should tell you which DLL(s) are the right ones to load for your environment; using the example of the Dapper package:

    C:\Program Files\PackageManagement\NuGet\Packages\Dapper.1.50.4\lib\net451\Dapper.dll
    C:\Program Files\PackageManagement\NuGet\Packages\Dapper.1.50.4\lib\netstandard1.3\Dapper.dll
    C:\Program Files\PackageManagement\NuGet\Packages\Dapper.1.50.4\lib\netstandard2.0\Dapper.dll
    
  • Given that .NET Standard DLLs run on all .NET platforms, however, you can programmatically look for the (latest) such DLLs and load them:

    (Get-Item (Join-Path (Split-Path (Get-Package Dapper).Source) lib/netstandard*) | 
      Sort-Object { [version] ($_.Name -replace '^netstandard') })[-1] |
        Get-ChildItem -Filter *.dll -Recurse |
          ForEach-Object { Add-Type -LiteralPath $_.FullName }
    
    • The above looks for the highest available .NET Standard version DLLs; if you want to target a specific version, the command becomes easier; e.g., for .NET Standard 2.0:

      Get-ChildItem -Recurse -Filter *.dll -LiteralPath (Join-Path (Split-Path (Get-Package Dapper).Source) lib/netstandard2.0) |
        ForEach-Object { Add-Type -LiteralPath $_.FullName }
      

BACON points out that the above is not enough if the package has dependencies that must be loaded too:

The one (not-so-trivial) step that's missing is loading any dependencies that may have been installed, too. Because the Dependencies property doesn't contain enough information, it seems that would involve extracting the .nuspec file from the .nupkg file in the Source directory, reading the <group> for the appropriate framework, and loading those packages' assemblies.

Are you using Powershell 5? Because if you are, it has a package management module:

It appears to be open source: https://github.com/OneGet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!