請教關於.Net Core Web API with Angular發布的問題

詹 志仁 20 信誉分
2024-02-02T08:54:15.8233333+00:00

您好:

我參考此篇官方文件

https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-asp-net-core-with-angular?view=vs-2022

建立一個ASP.NET Core app with Angular的網站,並參考下面的Q&A

https://learn.microsoft.com/en-us/answers/questions/1188745/how-to-publish-asp-net-with-angular-application

也能順利地發布到Azure雲端上了,目前網站運行順利。

但是我檢視Azure上發布網站目錄的結構,發現他deploy是在/site/wwwroot下再建立一個wwwroot的directory來存放angular client的程式碼,也就是angular client的程式碼是放在/site/wwwroot/wwwroot/... 目錄下。

想請教有辦法更改預設發布的資料夾名稱嗎?譬如我想將angular的程式碼發布到: wwwroot/ClientApp/dist/...下,後端dll程式碼仍維持在wwwroot/...下,謝謝。

ps: 我有科普找到類似的Q&A

https://stackoverflow.com/questions/75437392/change-angular-output-directory-from-wwwroot-to-another-folder-in-asp-net

但是跟著修改program.cs跟.csproj跟angular.json發布成功,但網站無法運行,可能是環境不同或是需要另外需要安裝SPA相關套件就不得而知了~

ASP.NET Core
ASP.NET Core
.NET Framework 中一套用于生成 Web 应用程序和 XML Web 服务的技术。
24 个问题
0 个注释 无注释
{count} 票

接受的答案
  1. JasonPan - MSFT 4,386 信誉分 Microsoft 供应商
    2024-02-02T12:17:13.22+00:00

    你好 @詹 志仁

    首先我先分享下您想要的測試結果。 User's image

    這裏我需要向您闡述的是,在基於Angular with Asp.net Core項目的模板創建的項目,是前後端分離的,與之前的 SPA 項目的區別是, 原先的前端項目是存放在Asp.net Core項目ClientApp文件夾下的。

    所以基於Angular with Asp.net Core項目的模板創建的項目,我們可以看成是獨立的兩個單純的項目,如果沒有進行項目引用的話。 那麽獨立的Asp.net Core項目是前後端分離設計中的Web API項目。 單純創建Web API項目 和這個模板創建的都是一樣的,不包含 wwwroot文件夾。

    這就是爲什麽您提到的,發佈後文件中會有wwwroot文件夾,因爲 我們需要讀取Angualr項目編譯後的靜態文件,從 app.UseStaticFiles(); 中間件我們也可以知道, 這將會默認可以讀取 類似MVC 項目中 wwwroot下的靜態資源文件。 所以這就是發佈后的文件中存在wwwroot文件夾的原因。 這是默認的行爲。 在這裏,我是非常不推薦您修改成ClientApp/dist的。 這將會破壞一些默認配置,測試時候暫時未遇到。

    截圖中的那個 C:\home\site\wwwroot> 路徑是App Service的默認存放 App的路徑,這樣您看起來,就是可以看到在默認路徑下還有一個wwwroot文件夾。 它們的含義是不一樣的, 第一個是App Service 默認讀取發佈文件的路徑, 第二個是Asp.net Core讀取靜態資源的路徑。
    User's image

    您問題中的兩個論壇鏈接中的分享方案,都是我進行測試后編輯它們都是的版本都是基於 小於等於.NET 7.0的,在.NET 8 會有細微的變化,這就是您爲什麽無法正常使它工作的原因。

    我不建議您糾結這兩個wwwroot的文件夾,但同時我也會分享如何在.NET 8.0中實現此需求,另外請注意,我暫時沒有找到辦法將ClientApp文件夾下的文件名修改成dist。請查看我的下面的測試代碼和配置。

    第一步:修改Program.cs中的靜態資源的中間件

    
    using Microsoft.Extensions.FileProviders;
    
    namespace AngularApp.Server
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                var builder = WebApplication.CreateBuilder(args);
    
                // Add services to the container.
    
                builder.Services.AddControllers();
                // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
                builder.Services.AddEndpointsApiExplorer();
                builder.Services.AddSwaggerGen();
    
                var app = builder.Build();
    
                app.UseDefaultFiles();
                //app.UseStaticFiles();
                // 修改靜態資源的讀取路徑,默認爲發佈後文件的wwwroot文件夾
                app.UseStaticFiles(new StaticFileOptions
                {
                    FileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "ClientApp", "angularapp.client", "browser")),
                    RequestPath = ""
                });
                // Configure the HTTP request pipeline.
                if (app.Environment.IsDevelopment())
                {
                    app.UseSwagger();
                    app.UseSwaggerUI();
                }
    
                app.UseHttpsRedirection();
    
                app.UseAuthorization();
    
    
                app.MapControllers();
    
                app.MapFallbackToFile("/index.html");
    
                app.Run();
            }
        }
    }
    
    

    第二步:創建文件夾,否則編譯會遇到文件夾問找到的錯誤訊息 User's image

    第三步:修改.csproj 文件

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
    	<PropertyGroup>
    		<TargetFramework>net8.0</TargetFramework>
    		<Nullable>enable</Nullable>
    		<ImplicitUsings>enable</ImplicitUsings>
    		<InvariantGlobalization>true</InvariantGlobalization>
    		<SpaRoot>..\angularapp.client</SpaRoot>
    		<SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
    		<SpaProxyServerUrl>https://localhost:4200</SpaProxyServerUrl>
    	</PropertyGroup>
    
    	<ItemGroup>
    		<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="8.*-*" />
    		<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
    	</ItemGroup>
    
    	<ItemGroup>
    		<ProjectReference Include="..\angularapp.client\angularapp.client.esproj">
    			<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
    		</ProjectReference>
    	</ItemGroup>
    
    	<ItemGroup>
    	  <Folder Include="ClientApp\angularapp.client\browser\" />
    	</ItemGroup>
    
    	<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    		<!-- 確保 Node.js 和 npm 安裝 -->
    		<Exec Command="node --version" ContinueOnError="true">
    			<Output TaskParameter="ExitCode" PropertyName="NodeInstalled" />
    		</Exec>
    		<Error Condition="'$(NodeInstalled)' != '0'" Text="Node.js is required to build and run this project." />
    
    		<!-- 安裝 Angular 應用的依賴 -->
    		<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    	</Target>
    
    	<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    		<!-- 在發佈前構建 Angular 應用 -->
    		<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build --prod" />
    
    		<!-- 確保 Angular 構建的靜態文件被包括在輸出文件中 -->
    		<ItemGroup>
    			<DistFiles Include="$(SpaRoot)\dist\**" />
    			<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')">
    				<RelativePath>ClientApp\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
    				<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    				<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    			</ResolvedFileToPublish>
    		</ItemGroup>
    	</Target>
    	<Target Name="CleanWwwroot" AfterTargets="Publish">
    		<!-- 刪除wwwroot文件夾 -->
    		<Message Text="Deleting wwwroot directory..." Importance="high" />
    		<Exec Command="rd /s /q $(PublishDir)wwwroot" />
    	</Target>
    
    </Project>
    
    

    如果答案是正确的,请点击“接受答案”并点赞。 如果您对此答案还有其他疑问,请点击“评论”。 注意:如果您想接收相关电子邮件,请按照我们的文档中的步骤启用电子邮件通知 此线程的通知。

    Best Regards

    Jason Pan

    1 个人认为此答案很有帮助。
    0 个注释 无注释

1 个其他答案

排序依据: 非常有帮助
  1. 詹 志仁 20 信誉分
    2024-02-02T13:23:44.7966667+00:00

    @JasonPan - MSFT Thank you so so much!!
    我終於明白了,感謝您詳細的解釋及範例解說。 另外想請問<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="8.-" /> 和

    <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    		<!-- 確保 Node.js 和 npm 安裝 -->
    		<Exec Command="node --version" ContinueOnError="true">
    			<Output TaskParameter="ExitCode" PropertyName="NodeInstalled" />
    		</Exec>
    		<Error Condition="'$(NodeInstalled)' != '0'" Text="Node.js is required to build and run this project." />
    
    		<!-- 安裝 Angular 應用的依賴 -->
    		<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    	</Target>
    
    	<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    		<!-- 在發佈前構建 Angular 應用 -->
    		<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build --prod" />
    
    		<!-- 確保 Angular 構建的靜態文件被包括在輸出文件中 -->
    		<ItemGroup>
    			<DistFiles Include="$(SpaRoot)\dist\**" />
    			<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')">
    				<RelativePath>ClientApp\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
    				<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    				<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    			</ResolvedFileToPublish>
    		</ItemGroup>
    	</Target>
    

    一定要加到csproj裡面嗎?因為官方下載的ASP.NET Core app with Angular的範本裡面預設沒有這些設定,沒有加這些設定我目前開發的網站仍可以正常運作。

    另外非常感謝您的範例程式碼,我原本想再請教為什麼我都沒做任何變更,就用預設的app.UseStaticFiles();,然而我發現在localhost端測試完全沒問題,deploy到Azure後,原本正常的網頁前端angular導到其他頁面或手動重整網頁一直出現404錯誤,原來我不小心把app.MapFallbackToFile("/index.html"); 給刪掉了,所以弄到現在才發現原因,真的太感謝了。