(四)學習了解OrchardCore筆記——將模塊的名字添加到程序集的ModuleName

  關於如何將模塊名添加到程序集的ModuleName說簡單吧也簡單,說不簡單吧也不簡單。

  簡單的原因是代碼只有幾行,不簡單的原因是這些都不是c#,都是MSbuild的代碼。這可真難為我了,所以這個地方我卡了兩個星期。

  首先我們來看下解決方案的目錄:

  都知道這些文件夾都是解決方案文件夾,但是build解決方案文件夾里放的是什麼,居然不是項目?不是項目如何調用呢,這可觸及我的知識盲點。經過多方查閱資料和博問上提問,我重於搞清楚了。

  首先,這兩個.yml文件刪了也無所謂,我第一次見到yml文件還是在docker的配置上,也就是一個跟我們常用的json一樣的配置文件(用縮進代替json裏面那堆括號,有人覺得這樣比較方便)。開始我還以為是通過其它程序靠yml配置文件注入模塊,被誤導了好久,這兩個配置文件就是持續集成的配置文件(沒進過大廠不懂這些被浪費好久),也就是項目發佈到github會自動幫你build等等。

  其次,就是剩下的文件是靠Directory.Build.props和Directory.Build.targets調用到項目里的。這就是我的第二個知識盲點了。我們打開文件夾(直接打開資源管理器的,不是visual studio的),可以發現src源碼文件夾下的OrchardCore、OrchardCore.Modules和OrchardCore.Themes三個文件夾都有Directory.Build.props和Directory.Build.targets這兩個文件。這意味着還有文件不在項目里?這又怎麼用呢?我真是快崩潰了!經過查找資料,重要明白:在MSBuild15以後新增一個功能就是讓開發者可以自己定義項目信息放在一個文件,這個文件會在Microsoft.Common.props和Microsoft.Common.target引用,而且會在csproj項目文件所在的文件夾開始尋找,只要找到存在Directory.Build.props和Directory.Build.target文件就會自動導入裏面的內容。也就是從項目的csproj當前項目開始自動向上尋找Directory.Build.props和Directory.Build.target,直到解決方法根目錄,只要找到立即停止。這就是意味着每個項目編譯的時候會把這些文件給包括進來。

  好了,明白了這些後,開始按順序了解模塊的加載過程。

  我是從啟動項目OrchardCore.Cms.Web開始看,它項目引用了OrchardCore.Application.Cms.Core.Targets,而這個項目又引用了OrchardCore.Application.Targets,這下Targets項目都在OrchardCore文件夾下,也就是編譯的時候會包含上面說的Directory.Build.props和Directory.Build.targets文件。

  OrchardCore.Application.Targets裏面只有一個OrchardCore.Application.Targets.targets文件,打開如下:

<Project xmlns="//schemas.microsoft.com/developer/msbuild/2003">

  <!-- 
    This file is packaged with "OrchardCore.Application.Targets.nupkg" in "./build" such that any
    Application that references it will embed in its assembly a list of the referenced modules.
  -->

  <Target Name="ResolveModuleProjectReferences" AfterTargets="AfterResolveReferences">
    <MSBuild
      Targets="GetModuleProjectName"
      BuildInParallel="$(BuildInParallel)"
      Projects="@(_MSBuildProjectReferenceExistent)"
      Condition="'@(_MSBuildProjectReferenceExistent)' != ''"
      SkipNonexistentTargets="true"
      ContinueOnError="true">

      <Output ItemName="ModuleProjectNames" TaskParameter="TargetOutputs" />
    </MSBuild>

    <ItemGroup>
      <ModuleNames Include="@(ModulePackageNames);@(ModuleProjectNames)" />
    </ItemGroup>

    <ItemGroup>
      <AssemblyAttribute Include="OrchardCore.Modules.Manifest.ModuleNameAttribute" Condition="'@(ModuleNames)' != ''">
        <_Parameter1>%(ModuleNames.Identity)</_Parameter1>
      </AssemblyAttribute>
    </ItemGroup>
  </Target>

  <Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile">
    <PropertyGroup>
      <NoWarn>$(NoWarn);0436</NoWarn>
    </PropertyGroup>
  </Target>

</Project>

   看到AssemblyAttribute元素了吧,沒錯,這就是程序集的屬性啊,在看看它裏面有啥?OrchardCore.Modules.Manifest.ModuleNameAttribute,沒錯,這個就是上篇反射找到的ModuleName,那麼怎麼來的呢,有個Condition=”‘@(ModuleNames)’ != ””,明顯這個條件就是ModuleNames元素不為空,然後獲取ModuleNames元素的Identity。那麼我們順着往上看就可以看到上個ItemGroup元素裏面就包含ModuleNames,但是沒有Identity屬性啊,只能查閱資料了,誰叫我MSbuild兩眼一抹黑呢,根據msdn介紹明白Identity就是Include屬性中指定的項,大家也可以看看msdn。那麼我們接着看INclude,@(ModulePackageNames);@(ModuleProjectNames),分號間隔符,間隔而已,繼續看看第二個ModuleProjectNames,上面的MSBuid的Oupt就是了,而任務呢,就是MSBuild的GetModuleProjectName。這個任務在哪呢,感覺很無厘頭是不是,不對,前面不是介紹了Directory.Build.props和Directory.Build.targets嗎,沒錯,往裏面找,打開Directory.Build.targets看看

<Project xmlns="//schemas.microsoft.com/developer/msbuild/2003">

  <Import Project="..\OrchardCore.Build\OrchardCore.Commons.targets" />
  <Import Project="..\OrchardCore\OrchardCore.Module.Targets\OrchardCore.Module.Targets.targets" />

  <PropertyGroup>
    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
  </PropertyGroup>

</Project>

  看到裏面包含了的OrchardCore.Module.Targets.targets文件沒有,打開接着看(這個有點長直接看最後部分):

 

<Project xmlns="//schemas.microsoft.com/developer/msbuild/2003">

  ...

  <Target Name="GetModuleProjectName" Returns="@(ModuleProjectName)">
    <ItemGroup>
      <ModuleProjectName Include="$(AssemblyName)" />
    </ItemGroup>
  </Target>

</Project>

  看到Name為GetModuleProjectName的Target任務了吧,請注意這個文件的位置,在..\OrchardCore\OrchardCore.Module.Targets\OrchardCore.Module.Targets.targets,沒錯就在OrchardCore.Module.Targets項目里,而所有模塊都是以用這個項目,也就是說所有應用這個項目的項目名都會加到程序集的ModuleName上!