問題描述
當本地環境中安裝.NET 6.0後,用指令 dotnet new web 或 dotnet new console 生成的專案,使用的都是新模板生成的Program.cs檔案。裡面去掉了namespace, class 以及main函式的定義。使得程式碼更簡潔。
生成的 Program.cs 程式碼為:
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();
與示例程式碼中所使用的程式碼結構差距十分巨大(示例連結:https://docs.microsoft.com/en-us/azure/azure-web-pubsub/tutorial-subprotocol?tabs=csharp):
using Azure.Messaging.WebPubSub; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Azure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace logstream { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddAzureClients(builder => { builder.AddWebPubSubServiceClient(Configuration["Azure:WebPubSub:ConnectionString"], "stream"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/negotiate", async context => { var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>(); var response = new { url = service.GetClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri }; await context.Response.WriteAsJsonAsync(response); }); }); } } }
那麼如何來定義 ConfigureServices, 如何來 Configure 中的程式碼呢?如何來解決 CS8803 : Top-level statements must precede namespace and type declarations
問題分析
這是程式碼由.NET 5.0 到 .NET 6.0的升級轉換問題。
在.NET 6 之前,每一個應用程式都將應用的初始化程式碼拆分放在 Program.cs 和 Startup.cs 檔案中。他們是兩個獨立的類,而在.NET 6.0中,為了簡潔,為了最小化API,把兩個類進行了合併。生成新的Program.cs中去掉了名稱空間(Namespace, Class定義, Main函式)。使得在啟動一個應用時,程式碼達到最少。 (PS:C# 編譯器會自動生成Mian函式)
在檢視官方對於5.0 變為 6.0的文件介紹:https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio
- ConfigureServices 函式裡面的 services.AddXXXXX()等都可以轉換為 builder.Services.AddXXXXX()
- Configure 函式中的內容,可以直接寫在 var app = builder.Build(); 程式碼之後。
所以,本文之前的程式碼,可以直接轉換為:
using Azure.Messaging.WebPubSub; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Azure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var ConnectionString = ""; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAzureClients(builder => { builder.AddWebPubSubServiceClient(ConnectionString, "stream"); }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/negotiate", async context => { var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>(); var response = new { url = service.GetClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri }; await context.Response.WriteAsJsonAsync(response); }); }); app.MapGet("/", () => "Hello World!"); app.Run();
特別注意,在新模板下的程式碼,非常容易出現:CS8803 : Top-level statements must precede namespace and type declarations 錯誤。這是因為 .NET 6.0在隱藏了Main函式後,在編譯程式碼時候,會自動補上Main函式,所以在Program.cs 的程式碼中,如果需要定義其他類,必須放在檔案的末尾,不能在檔案開頭部分和中間。
當Class定義程式碼放在Program.cs開頭部分
當Class定義程式碼放在Program.cs中間部分
當Class定義程式碼放在Program.cs結尾部分
更多關於Top-level statements的說明,請見:https://www.cnblogs.com/lulight/articles/16285885.html