以编程方式获取nuget包的路径 [英] Getting the path of a nuget package programmatically

查看:74
本文介绍了以编程方式获取nuget包的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在安装一个带有可执行文件的nuget软件包.要从解决方案中的可执行文件 引用到项目文件(更具体地讲是在mvc控制器中)中,目前,我需要对文件夹路径进行硬编码,这特别值得一提,因为它的版本号为它.因此,当我更新nuget软件包时,需要更改所有这些引用.

这似乎很愚蠢

我对Microsoft堆栈还很陌生,但是没有某种方法可以仅请求nuget依赖项的路径吗?

解决方案

在使用NuGet进行程序包管理器时,添加新程序包时会发生的情况是NuGet从存储库中提取依赖项,并将文件添加到特定的程序包目录中(其位置取决于解决方案本地NuGet配置中的值),并将软件包"lib"文件夹中的所有文件添加为对项目的引用.其他目录(例如工具,src等)中的文件用于其他目的,但不会添加为引用(除非在install.ps1脚本中手动完成).

在构建二进制文件时,与诸如node.js之类的解释语言的区别之一就变得很重要.在构建过程中,编译器将引用复制到输出目录.这意味着在执行实际代码时,包的位置几乎无关紧要,因为此代码位于其他位置的二进制文件中(通常,您仅将二进制文件而不是整个解决方案文件夹复制到服务器).

因此,根据所需可执行文件在软件包中的位置,有几种方案:

  • 如果可执行文件是程序包"lib"文件夹,则您的ASP.MVC项目应引用该可执行文件.在这种情况下,可执行文件将被复制到输出目录.在这种情况下,您可以通过执行以下代码来获取可执行路径:

     //这将返回包含"MyClass"类型的程序集的URI,//例如:file:///C:\ temp \ myassembly.dllvar codeBase = typeof(MyClass).Assembly.CodeBase;//这将返回没有任何URI限定符的文件路径var location = new Uri(codeBase).LocalPath; 

  • 如果该可执行文件不在程序包的'lib'文件夹中,则在这种情况下不会对其进行引用,因此该可执行文件也将不在二进制文件夹中.这意味着您需要将二进制文件复制到二进制文件夹.一种简单的方法是使用构建前或构建后事件.使用此功能的缺点是,每次更新软件包时都需要更新构建事件,因为文件夹名称包含软件包的版本,因此会更改.如果您不想这样做,则可以使用一些MsBuild魔术来设置一个系统,该系统可以处理更改的文件夹名称.

    • 首先,您需要找到包含可执行文件的文件夹.以下MsBuild脚本可用于在程序包目录(NuGet解压缩程序包的目录)中搜索给定文件(在您的情况下为可执行文件).将此脚本放在您可以从项目文件中引用它的位置(例如,在解决方案目录中)

       < Project xmlns ='http://schemas.microsoft.com/developer/msbuild/2003'ToolsVersion ="4.0"><!-查找由NuGet安装的工具的完整路径定义:-PackagesDir:包含已安装"软件包的目录.-FileToLocate:路径应位于其中的可执行文件的名称.-路径:返回变量,包含可执行文件的完整路径.->< UsingTask TaskName ="FindToolDirectoryFromPackages"TaskFactory ="CodeTaskFactory"AssemblyFile ="$(MSBuildToolsPath)\ Microsoft.Build.Tasks.v4.0.dll">< ParameterGroup>< PackagesDir ParameterType ="System.String"必需="true"/>< FileToLocate ParameterType ="System.String"必需="true"/>< Path ParameterType ="System.String" Output ="true"/></ParameterGroup><任务><使用命名空间="System.Linq"/>< Code Type =片段" Language ="cs"><![CDATA [路径= System.IO.Directory.EnumerateFiles(PackagesDir,FileToLocate,SearchOption.AllDirectories).OrderBy(k => System.IO.Path.GetDirectoryName(k)).Select(k => System.IO.Path.GetDirectoryName(k)).LastOrDefault();]]></代码></任务></UsingTask></Project> 

    • 接下来,您需要更新ASP.MVC项目文件.如果您将上述MsBuild脚本添加到解决方案文件夹,则首先将以下行添加到项目文件的第一个 PropertyGroup

       < SolutionDir Condition ='$(SolutionDir)'==''或'$(SolutionDir)'=='* undefined *'"> $(MSBuildProjectDirectory)\ ..</SolutionDir> 

    • 在项目文件的底部,有两个带有注释的目标,一个称为BeforeBuild,另一个称为AfterBuild.取消注释之一,哪一个都不重要.然后添加以下代码:

       < FindToolDirectoryFromPackages PackagesDir ="$(SolutionDir)\ .. \ RELATIVE_PATH_TO_PACKAGE_DIRECTORY"FileToLocate ="FILE_NAME_OF_EXECUTABLE"><输出TaskParameter ="Path" PropertyName ="DirMyExecutableFile"/></FindToolDirectoryFromPackages>< ItemGroup>< Files Include ="$(DirMyExecutableFile)\ ** \ *.*"/></ItemGroup><!-OutputPath应该是编译器将二进制文件复制到的目录->< MakeDir Directories ="$(OutputPath)"Condition =!Exists('$(OutputPath)')"/><复制SourceFiles ="@(Files)"DestinationFolder ="$(OutputPath)\%(RecursiveDir)"/> 

在每次构建项目时都要完成所有这些操作,然后将可执行文件复制到输出目录,然后可以从代码中调用可执行文件.

I'm installing a nuget package with an executable in it. To reference the executable from within the solution in a project file (more specifically in an mvc controller), at the moment I need to hardcode the folder path, which is particularly annyoing since it has a version number in it. So when I update the nuget package, I'd need to change all these references.

That seems silly

I'm still fairly new to the microsoft stack, but isn't there some way to just request the path of a nuget dependency?

解决方案

When using NuGet for package manager what happens when a new package is added is that NuGet pulls in the dependencies from the repository, adds the files to a specific package directory (the location of which depends on the values in the solution local NuGet configuration) and adds all the files in the package 'lib' folder as references to the project. Files in other directories (e.g. tools, src etc.) are used for other purposes but they will not be added as references (unless manually done in a install.ps1 script).

One of the difference with an interpreted language like node.js becomes important when you build your binaries. During the build process the compiler copies the references to the output directory. This means that the location of your packages is mostly irrelevant when you execute the actual code because this code lives in a binary in a different location (and in general you only copy the binaries and not the entire solution folder to the server).

So depending on where the desired executable is in the package there are several scenario's:

  • If the executable is the package 'lib' folder then it should be referenced by your ASP.MVC project. In that case the executable will be copied to the output directory. In that case you can get hold of the executable path by executing the following code:

    // This returns the URI of the assembly containing the 'MyClass' type, 
    // e.g.: file:///C:\temp\myassembly.dll
    var codeBase = typeof(MyClass).Assembly.CodeBase;
    
    // This return the file path without any of the URI qualifiers
    var location = new Uri(codeBase).LocalPath;
    

  • If the executable is not in the package 'lib' folder in which case it is not referenced and thus won't be in the binary folder. Which means you need to copy the binaries to your binary folder. An easy way to do this is to use the pre- or post-build events. The drawback of using this is that you need to update the build event every time you update your package because the folder name includes the package version and will thus change. If you don't want to do this then with the use of some MsBuild magic you can set up a system that allows you to handle the changing folder name.

    • First you need to be able to find the folder that holds your executable. The following MsBuild script can be used to search your package directory (the one where NuGet unpacks the packages) for a given file (in your case the executable file). Put this script in a location where you can reference it from your project file (e.g. in your solution directory)

      <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' 
               ToolsVersion="4.0">
          <!--
              Finds the full path for a tool that was installed by NuGet
              Define:
              - PackagesDir: Directory that contains the 'installed' packages.
              - FileToLocate: Name of the executable file for which the path should be located.
              - Path: Return variable containing the full path of the executable file.
          -->
          <UsingTask TaskName="FindToolDirectoryFromPackages" 
                     TaskFactory="CodeTaskFactory" 
                     AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
              <ParameterGroup>
                  <PackagesDir ParameterType="System.String" Required="true" />
                  <FileToLocate ParameterType="System.String" Required="true" />
                  <Path ParameterType="System.String" Output="true" />
              </ParameterGroup>
              <Task>
                  <Using Namespace="System.Linq" />
                  <Code Type="Fragment" Language="cs">
                      <![CDATA[
                          Path = System.IO.Directory.EnumerateFiles(PackagesDir, FileToLocate, SearchOption.AllDirectories)
                              .OrderBy(k => System.IO.Path.GetDirectoryName(k))
                              .Select(k => System.IO.Path.GetDirectoryName(k))
                              .LastOrDefault();
                      ]]>  
                  </Code>
              </Task>
          </UsingTask>
      </Project>
      

    • Next you need to update your ASP.MVC project file. If you added the above MsBuild script to the solution folder then first add the following line to the very first PropertyGroup of your project file

      <SolutionDir Condition="'$(SolutionDir)' == '' or '$(SolutionDir)' == '*undefined*'">$(MSBuildProjectDirectory)\..</SolutionDir>
      

    • At the bottom of your project file are two commented targets, one called BeforeBuild and one called AfterBuild. Uncomment one, it doesn't really matter which one. Then add the following code:

      <FindToolDirectoryFromPackages PackagesDir="$(SolutionDir)\..\RELATIVE_PATH_TO_PACKAGE_DIRECTORY" 
                                     FileToLocate="FILE_NAME_OF_EXECUTABLE">
          <Output TaskParameter="Path" PropertyName="DirMyExecutableFile" />
      </FindToolDirectoryFromPackages>
      
      <ItemGroup>
          <Files Include="$(DirMyExecutableFile)\**\*.*" />
      </ItemGroup>
      
      <!-- OutputPath should be the directory to which the compiler will copy your binaries -->
      <MakeDir Directories="$(OutputPath)" 
               Condition="!Exists('$(OutputPath)')" />
      <Copy SourceFiles="@(Files)" 
            DestinationFolder="$(OutputPath)\%(RecursiveDir)" />
      

With all this done every time you build your project the executable should be copied to your output directory and then you can call the executable from your code.

这篇关于以编程方式获取nuget包的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆