以编程方式获取nuget包的路径

时间:2014-03-24 17:19:13

标签: c# .net nuget

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

这看起来很傻

我仍然是微软堆栈的新手,但是有没有办法只是请求一个nuget依赖的路径?

1 个答案:

答案 0 :(得分:6)

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

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

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

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

    // 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;
    
  • 如果可执行文件不在包'lib'文件夹中,在这种情况下它不会被引用,因此不会在二进制文件夹中。这意味着您需要将二进制文件复制到二进制文件夹。一种简单的方法是使用构建前或构建后事件。使用它的缺点是每次更新包时都需要更新构建事件,因为文件夹名称包含软件包版本,因此会更改。如果您不想这样做,那么使用一些MsBuild魔法,您可以设置一个系统,允许您处理更改的文件夹名称。

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

      <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>
      
    • 接下来,您需要更新ASP.MVC项目文件。如果您将上述MsBuild脚本添加到解决方案文件夹,那么首先将以下行添加到项目文件的第一个PropertyGroup

      <SolutionDir Condition="'$(SolutionDir)' == '' or '$(SolutionDir)' == '*undefined*'">$(MSBuildProjectDirectory)\..</SolutionDir>
      
    • 在项目文件的底部有两个注释目标,一个名为BeforeBuild,另一个名为AfterBuild。取消注释,哪一个并不重要。然后添加以下代码:

      <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)" />
      

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