這是改寫 ASP.NET Core 後的一大困擾,ASP.NET Core 預設會將 .cshtml 編譯成 YourApp.Views.dll,不再像以前可以直接修改 Views 資料夾下的 .cshtml,重新整理瀏覽器就看修改後的結果。必須停止偵錯,重新編譯執行才會更新。

這項調整讓我的前端程式開發過程變得很痛苦,我採用「輕前端」的開發策略,cshtml 是主體,JavaScript 部分只用 Vue.js 處理 MVVM 及用 AJAX 方式呼叫 WebAPI,因此常要反覆調整 HTML 元素的 v-model、v-bind、v-on 標籤及 CSS 樣式等,每動一個地方想看結果就得停止偵錯、重新編譯,再重新偵錯,看瀏覽器關了又開、開了又開,火都上來了。過去 MVC5 那種改 cshtml 後存檔 + 瀏覽器重整看結果的開發程序才是正常人能忍受的開發方式吧!

研究找到解決方案。在 MS 文件查到,ASP.NET Core 3.1 起支援所謂的 Razor Runtime Compilation,允許 Razor Pages 或 MVC 啟用 cshtml 動態編譯,恢復 MVC5 時代存檔重整即更新的模式。而從 VS2019 16.5.4 起(依文件釋出日期 4/14 推測),新增 ASP.NET Core 專案時會多一個「Enable Razor runtime compilation」選項:(實測要 ASP.NET Core 3.1 以後才會有這個選項)

勾選後,專案會多參照一個 Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation Package:

而 Properties/launchSettings.json 則有一個 ASPNETCORE_HOSTINGSTARTUPASSEMBLIES 變數啟用 cshtml 執行期編譯:

  //... 略
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation"
      }
    }
    //... 略

如果是已經建立好的 ASP.NET Core 3.1 專案,可以手動安裝 Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation NuGet Package,比照上述方式加入 ASPNETCORE_HOSTINGSTARTUPASSEMBLIES 參數。MS 文件提到 Startup.ConfigureServices() 加上 services.AddRazorPages().AddRazorRuntimeCompilation() 的做法,不如 用 ASPNETCORE_HOSTINGSTARTUPASSEMBLIES 變數動態切換來方便。

註:Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 需要 .NET Core 3.1 以上版本,不適用 ASP.NET Core 2.x。

一般來說,cshtml 動態編譯在開發階段比較有用,在線上環境會因為動態編譯及啟用 .NET Core File Watcher 損失一些效能,而部署 .cshtml 檔案還會增加原始碼外洩及被惡意竄改的風險,較不建議使用。故預設 Publish 時,.cshtml 預設還是會編譯成 AppName.Views.dll,輸出結果也不會包含 Views 或 Pages 資料夾,若你有很好的理由要在正式環境啟用,可在 .csproj 加入 RazorCompileOnPublish 屬性設成 false (預設為 true):

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>
    <RazorCompileOnPublish>false</RazorCompileOnPublish>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.3" />
  </ItemGroup>

</Project>

如此,輸出時將不會產生 AppName.Views.dll,MVC5 時代熟悉的 Views/Pages 資料夾也會回來囉。


Comments

# by Terence

謝謝大大的資訊, 小弟最近開始使用asp.net core開發, 覺得最困擾就是這件事...

# by wail

一直都覺得cshtml很麻煩 寫這東西都是一次定生死 以前的除錯都痛苦要命 現在改成要一直PLAY 真的讓人更想哭

# by Ike

推 dotnet watch + 啟動但不偵錯

Post a comment


72 + 21 =