VS上使用Nuget部分分析

ciscopuke發表於2021-09-09

VS上使用Nuget部分分析

介紹VS專案是如何使用Nuget的,如何還原包,如何處理包與專案之間的關係,如何複製Nuget包裡面檔案到專案

如何特殊說明,預設說的是 . Net Core專案,以及VS2017

Nuget包還原過程

  • 各位同學可能都注意到第一次還原專案之後,專案多了個obj資料夾,裡面多了一些檔案,專案名+".nuget.*",另外還有個project.assets.json檔案,Nuget就是利用這個檔案開始工作,利用此檔案執行了ResolveNuGetPackageAssets任務

  • 首先看這個檔案C:Program Files (x86)Microsoft Visual Studio2017EnterpriseMSBuildMicrosoftNuGet15.0Microsoft.NuGet.targets,現在解析一下這個檔案幹了什麼事情

  • 1.使用匯入任務,也就是匯入dll裡面的任務

  • 2.根據以下順序標識專案的asset/lock檔案,即給$(ProjectLockFile)賦值,如果以下條件均不滿足,NuGet build targets就不會執行:

    • $(ProjectAssetsFile)如果已經宣告,則給$(ProjectLockFile)賦值,這意味著專案使用 [PackageReference] ( ect-files)

    • 如果$(RestoreProjectStyle)等於PackageReference(也就是專案使用的包管理格式為 [PackageReference] ( ect-files)),賦值$(BaseIntermediateOutputPath)project.assets.json

    • 如果存在project.json檔案,則使用project.lock.json

    • 如果上述條件均不滿足,assets or lock file都不存在,預設賦值$(BaseIntermediateOutputPath)project.assets.json

  • 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 Studio2017EnterpriseMSBuild15.0Microsoft.Common.TargetsImportAfterMicrosoft.NuGet.ImportAfter.targets匯入的,這個檔案只是匯入Microsoft.NuGet.targets而已。而該target應該有某種機制觸發的,並沒有找到在哪裡呼叫

總結

  • 透過對這些檔案的分析,再結合官方文件,一來可以瞭解VS專案從點選生成專案到出現編譯好的dll中間都發生了什麼事,二來我們可以參照這些例子,寫一些自己的target,比如測試或者釋出,每次build專案,觸發測試的target或者釋出的target。

  • 發現兩個比較有趣的東西如下:

    • Microsoft.NuGet.targets<FrameworkInjectionPackagesDirectory Condition="'$(FrameworkInjectionPackagesDirectory)' == ''">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINESOFTWARENuGetRepository', '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>
    

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4369/viewspace-2819149/,如需轉載,請註明出處,否則將追究法律責任。

相關文章