手记

VS上使用Nuget部分分析

VS上使用Nuget部分分析

介绍VS项目是如何使用Nuget的,如何还原包,如何处理包与项目之间的关系,如何复制Nuget包里面文件到项目

如何特殊说明,默认说的是 . Net Core项目,以及VS2017

Nuget包还原过程

  • 各位同学可能都注意到第一次还原项目之后,项目多了个obj文件夹,里面多了一些文件,项目名+".nuget.*",另外还有个project.assets.json文件,Nuget就是利用这个文件开始工作,利用此文件执行了ResolveNuGetPackageAssets任务

  • 首先看这个文件C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\NuGet\15.0\Microsoft.NuGet.targets,现在解析一下这个文件干了什么事情

  • 1.使用UsingTask导入任务,也就是导入dll里面的任务

  • 2.根据以下顺序标识项目的asset/lock文件,即给$(ProjectLockFile)赋值,如果以下条件均不满足,NuGet build targets就不会运行:

  • 3.添加MSBuildAllProjects以更好的支持增量构建

  • 4.检查运行时标识符,如果没有明确声明,设置为win;win-x86;win-x64

  • 5.设置依赖targets,写入ResolveNuGetPackageAssetsDependsOn,其中有个依赖target是ResolveProjectReferences,用来加载当前所依赖项目的

  • 6.执行TaskResolveNuGetPackageAssets,又分是否是AOT项目,主要输出了

    • @(Analyzer) - Paths to build-time diagnostic analyzers 构建时诊断分析路径
    • @(Reference) - Paths to build-time NuGet dependencies 构建时NuGet依赖关系路径
    • @(ReferenceCopyLocalPaths) - Paths to run-time dependencies to copy 复制到运行时依赖关系的路径
  • 7.执行完之后,将框架注入到混合应用,猜测是将结果注入到全局变量

  • 8.最后会导入$(MSBuildProjectDirectory)\$(MSBuildProjectName).nuget.targets$(MSBuildProjectDirectory)是项目路径,$(MSBuildProjectName)是项目名称,估计是用来启用自定义任务的,比如项目叫做MyProj,在项目新建MyProj.nuget.targets文件,Nuget Build之后会调用该target

猜测

  • 以上是对Microsoft.NuGet.targets的内容分析,主要是根据asset/lock文件进行Nuget 的 还原过程,每个Nuget包可能也含有target,需要解析,导入到项目运行。或者内容文件需要复制到项目,这一切的基础就是Microsoft.NuGet.targets
  • 通过文件内容搜索,Microsoft.NuGet.targets是由C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Microsoft.Common.Targets\ImportAfter\Microsoft.NuGet.ImportAfter.targets导入的,这个文件只是导入Microsoft.NuGet.targets而已。而该target应该有某种机制触发的,并没有找到在哪里调用

总结

  • 通过对这些文件的分析,再结合官方文档,一来可以了解VS项目从点击生成项目到出现编译好的dll中间都发生了什么事,二来我们可以参照这些例子,写一些自己的target,比如测试或者发布,每次build项目,触发测试的target或者发布的target。

  • 发现两个比较有趣的东西如下:

    • Microsoft.NuGet.targets<FrameworkInjectionPackagesDirectory Condition="'$(FrameworkInjectionPackagesDirectory)' == ''">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\NuGet\Repository', 'NetCoreSDK', null, RegistryView.Registry32, RegistryView.Default))</FrameworkInjectionPackagesDirectory>,可以看到HKEY_LOCAL_MACHINE,访问了注册表
    • target中的task可以直接写代码,导入Microsoft.Build.Tasks.v4.0.dll里面的Task,ReferenceUsingCode组合就可以直接写代码啦。一下内容写到Build.props,然后再项目文件导入,放在Project元素之下<Project><Import Project="Build.props" Condition="Exists('Build.props')" /></Project>
      <Project DefaultTargets="Build"     xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <Target Name = "BuildModelTarget" BeforeTargets="PrepareForBuild">
          <BuildModel1 />
        </Target>
        <UsingTask TaskName="BuildModel1"  TaskFactory="CodeTaskFactory" AssemblyFile="$  (MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
          <Task >
            <Reference Include="System" />
            <Reference Include="System.Management" />
            <Using Namespace="System" />
            <Using Namespace="System.Linq" />
            <Using Namespace="System.Diagnostics" />
            <Using Namespace="System.Management" />
            <Code Type="Fragment" Language="cs">
              <![CDATA[
                  throw new Exception("23333");
            ]]>
            </Code>
          </Task>
        </UsingTask>
      </Project>
    
0人推荐
随时随地看视频
慕课网APP