我正在安装一个带有可执行文件的nuget包。要在项目文件(更具体地说是在mvc控制器中)中引用解决方案中的可执行文件,目前我需要对文件夹路径进行硬编码,这特别是因为它具有版本号它。因此,当我更新nuget包时,我需要更改所有这些引用。
这看起来很傻
我仍然是微软堆栈的新手,但是有没有办法只是请求一个nuget依赖的路径?
答案 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)" />
每次构建项目时都会完成所有这些操作,应该将可执行文件复制到输出目录,然后可以从代码中调用可执行文件。