• 【Azure Developer】使用Azure PubSub服务示例代码时候遇见了.NET 6.0的代码转换问题


    问题描述

    当本地环境中安装.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

    1. ConfigureServices 函数里面的 services.AddXXXXX()等都可以转换为  builder.Services.AddXXXXX()
    2. 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

     

    参考资料

    Tutorial: Publish and subscribe messages between WebSocket clients using subprotocol: https://docs.microsoft.com/en-us/azure/azure-web-pubsub/tutorial-subprotocol?tabs=csharp Migrate from ASP.NET Core 5.0 to 6.0:https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio
  • 相关阅读:
    三、C语言常用运算符
    sqlserver数据库,创建作业,定时执行sql
    『现学现忘』Git后悔药 — 32、revert撤销(一)
    LAMP和LNMP架构详解
    Android BitmapUtil图片工具类
    MES生产执行解决方案提供商,可定制工厂MES精益制造管理系统-亿发
    Cron正则表达式总结汇总说明
    前端面经1
    (web前端网页制作课作业)使用HTML+CSS制作非物质文化遗产专题网页设计与实现
    platform驱动模型再叙
  • 原文地址:https://www.cnblogs.com/lulight/p/16285870.html