ASP.NET Core 6.0 如何处理丢失的 Startup.cs 文件

介绍

    .NET 6.0 已经发布,ASP.NET Core 6.0 也已发布。其中有不少变化让很多人感到困惑。例如,“谁动了我的奶酪”,它在哪里Startup.cs?在这篇文章中,我将深入研究这个问题,看看它移动到了哪里以及其他变化。

    ASP.NET Core 的中间件并没有发生根本性的变化,但部分项目结构以及注册依赖项的位置发生了变化。为了更好地理解它,最好从 .NET Core 3.1 项目模板开始,然后手动升级它,看看它与新模板相比如何。

升级旧式控制台项目

    首先,让我们创建一个新的控制台项目。我将其命名为OldToNew。我选择了 .NET Core 3.1 目标,并将其升级到 .NET 6.0 以查看差异。如果您已经使用 .NET 一段时间,您会在文件中认出这个项目结构Program.cs。 

using System;

namespace OldToNew
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

        在 .NET 6.0 中,这些变化旨在简化和消除应用程序中的冗余。他们引入的首批功能之一是所谓的Filescoped Namespaces。传统命名空间如下所示:

namespace OldToNew
{
    // code goes here.
}

        如果您已经使用过 .NET 一段时间,那么您可能从未在文件中放置过多个命名空间。您可以删除花括号,只需添加分号,将整个文件标记为使用一个命名空间。

namespace OldToNew;
// code goes here.
 

using System;

namespace OldToNew;

internal class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
    }
}
 

        Visual Studio 将会向我抱怨,因为这是一个 .NET Core 3.1 项目,所以在我们走得太远之前,我们需要编辑 .NET Core 3.1 .csproj 文件并将其转换为 .NET 6.0 应用程序。

<!-- .NET Core 3.1 -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

</Project>

<!-- .NET 6.0 -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

</Project>

        一旦我们做出这一改变,Visual Studio 就会对文件范围的命名空间感到满意。

        我们要做的下一个更改是删除该using System;行。为此,我们需要再次编辑项目文件并启用Implicit Usings。

<!-- .NET 6.0 -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

</Project>

        如果我们启用隐式 using 语句,我们通常使用的大多数常用 using 语句将默认包含在 SDK 中,您不再需要将它们包含在文件中。我们可以删除该using System;行,因为编译器会自动为我们添加 using 语句。

namespace OldToNew;

internal class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
    }

        他们引入的下一个功能是所谓的“顶级语句”。 其目的是删除每个控制台应用程序或 ASP.NET Core 应用程序中存在的“垃圾”。

        使用顶级语句,我们可以删除static void Main(string[] args)方法和花括号以及命名空间和class Program声明。

Console.WriteLine("Hello World!");

        一旦删除所有这些,您就会看到我们剩下的唯一代码就是我们的Console.WriteLine()方法!

将控制台应用更改为 Web 应用 (ASP.NET Core)

    目前,这只是一个简单的控制台应用程序,但我想将其转换为 ASP.NET Core 应用程序。在执行此操作之前,让我们先查看解决方案资源管理器中的依赖项和框架节点。

        您可以在上方看到,Frameworks这Microsoft.NETCore.App是包含创建控制台应用程序所需的所有包的 SDK。让我们将 .csproj 文件中的 SDK 类型更改为 .Web 类型项目,看看会发生什么Microsoft.NET.Sdk:Microsoft.NET.Sdk.Web。

<!-- .NET 6.0 -->
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

</Project>
注意现在依赖下发生的情况:

        该框架现在包括Microsoft.AspNetCore.App将引入创建 ASP.NET Core 应用程序所需的所有包。它还将修改全局 using 语句以包含 ASP.NET 特定的 using 语句。

        现在让我们删除该Console.WriteLine("Hello World!");行并添加 ASP.NET Core 特定的代码。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(); 

        我们现在正在构建一个 Web 应用程序。WebApplication对象从哪里来?它属于Microsoft.AspNetCore.Builder命名空间。

        我们可以运行这个应用程序,但是由于没有端点,所以会有点无聊。让我们添加一个端点来完成这个任务:

app.MapGet("/", () => {
    return "Hello World!";
});   

        我们刚刚在 ASP.NET Core 6.0 中创建了一个最小 API Web 应用程序。让我们运行它并看看会发生什么。 

        当我们启动默认路径时,它会返回,hello world因此我们有一个功能齐全的 Web 应用程序。最少的 API 是快速构建 Web API 项目的好方法。

Startup.cs 怎么样?

    ASP.NET Core 6.0 中的中间件流程与完整 Web API MVC 项目的流程类似,并且共享许多相同的实现。在以前的 ASP.NET Core 项目中,您将获得一个Startup.cs包含两个方法的类ConfigureServices()和Configure()。

    在 ConfigureServices()中,您注册了依赖项注入服务。在 Configure() 中,您概述了中间件管道顺序和结构。

    在我们的新项目中,这是什么样子的?您将依赖注入放在哪里?答案是在第一行和第二行之间,注册中间件在第二行和第三行之间,如下所示。

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.Run();

例如,如果我想添加身份验证,我会像这样注册: 

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
builder.Services.AddAuthentication(...) ...
builder.Services.AddAuthorization();
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => {
    return "Hello World!";
});  
app.Run();

        中间件管道中的顺序很重要,因此我在中间件MapGet()上方添加了UseAuthentication()和UseAuthorization()。但是,为了使其生效,您需要使用属性注释要保护的端点。这将需要使用语句[Authorize],必须引用:Microsoft.AspNetCore.Authorization 。

using Microsoft.AspNetCore.Authorization;

...

app.MapGet("/",[Authorize]() => {
    return "Hello World!";
});

Program.cs到目前为止,我们的文件的完整代码如下所示: 

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/",[Authorize] () => {
    return "Hello World!";
});  
app.Run(); 

        如果我们现在运行它,我们将会得到一个异常,因为我们从未指定身份验证方案。

        让我们修复它。我们可以选择多种不同类型的身份验证方案,但在 WebAPI 中,我们通常使用诸如 bearer token 或 JWT token 之类的东西来保护应用程序。

        让我们继续将 JWT 承载者添加到最小 API。我们需要Microsoft.AspNetCore.Authentication.JwtBearer通过 NuGet 导入包,然后添加以下代码:

using Microsoft.AspNetCore.Authentication.JwtBearer;

...

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();

所以完整的块应该是这样的:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);
// REGISTER SERVICES HERE
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
builder.Services.AddAuthorization();
var app = builder.Build();
// REGISTER MIDDLEWARE HERE
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", [Authorize] () => {
    return "Hello World!";
});
app.Run();

        JWT Bearer 已添加到应用程序中,让我们运行它并查看会发生什么。现在我们得到了我们正在寻找的状态,401 unauthorized因为我们没有为其提供任何类型的令牌。还需要其他步骤来设置获取令牌的方法并确保我们只允许接受有效的令牌,但这超出了本文的范围。本文的重点是演示在哪里注册依赖项和中间件以及如何使用它们。

        我们应该做的最后一项修改是将 [Authorize] 属性更改为使用“流畅的语法”,如下所示:

//FROM THIS:
app.MapGet("/", [Authorize] () => {
    return "Hello World!";
});

//TO THIS:
app.MapGet("/", () => {
  return "Hello World!";
}).RequireAuthorization();

它们都做同样的事情,但是在最小 API 情况下,“流畅的语法”感觉更自然。 

恢复丢失的 Startup.cs 文件

    接下来,让我们看看能否恢复我们的老朋友Startup.cs文件。如果将所有内容都放在一个文件中,最小 API 结构可能会变得混乱和臃肿。

    一定有办法让我们更好地组织这些。我将首先向Startup.cs项目添加一个名为的新类。

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

    }

     public void Configure(WebApplication app, IWebHostEnvironment env)
    {

    }

        这看起来应该与过去的完整 Web API 项目模板很相似。我只是将其粘贴到我的新Startup.cs文件中并删除了命名空间。该Startup.cs文件需要IConfiguration传入一个对象。我们可以从我们的 中提供该对象吗Program.cs? 

//  Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration); 

        是的。我们可以这样做。builder创建的对象包含一个Configuration属性,我们可以使用该属性将其传递给Startup构造函数。

        接下来,让我们尝试为该ConfigureServices()方法提供一个IServiceCollection。

//  Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services); 

        同样,builder包含一个Services我们可以用来传递给ConfigureServices()方法的属性。现在我们可以从中删除所有依赖注入代码Program.cs并将其移动到ConfigureServices中的方法Startup.cs。 

// Startup.cs file
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
    services.AddAuthorization();
}

接下来,让我们尝试Configure()WebApplication类提供方法。 

//  Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);

var app = builder.Build();

startup.Configure(app, builder.HostingEnvironment); 

        有趣的是,虽然我们传递的app是 类型WebApplication,但如果你检查它,该Configure()方法需要的是IApplicationBuilder,但它似乎没问题。为什么?如果你深入研究该WebApplication对象,你会看到它实现了IApplicationBuilder接口。

        我们将中间件管道代码剪切出来Program.cs,并将其粘贴到Configure()方法中Startup.cs。

// Startup.cs file
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  app.UseAuthentication();
  app.UseAuthorization();

  app.MapGet("/", () =>
  {
      return "hello world";
  }).RequireAuthorization();

  app.Run();
}

        不幸的是,这实际上行不通,因为接口IApplicationBuilder没有MapGet()方法或Run()方法。那些存在于WebApplication类中。如果我们将Configure()方法更改为接受WebApplication对象,它应该可以工作。 

// Startup.cs file
public void Configure(WebApplication app, IWebHostEnvironment env)
{
  app.UseAuthentication();
  app.UseAuthorization();

  app.MapGet("/", () =>
  {
      return "hello world";
  }).RequireAuthorization();

  app.Run();
}

让我们看一下完整的文件“Program.cs”和“Startup.cs”,看看它们现在是什么样子。 

// Program.cs file
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, builder.Environment);

// Startup.cs file
using Microsoft.AspNetCore.Authentication.JwtBearer;

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer();
        services.AddAuthorization();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(WebApplication app, IWebHostEnvironment env)
    {
        app.UseAuthentication();
        app.UseAuthorization();

        app.MapGet("/", () =>
        {
            return "hello world";
        }).RequireAuthorization();

        app.Run();
    }
}

        如果我们运行它,我们会得到401 Unauthorized状态,这意味着它正在运行。除了将我们的配置内容移到 中之外Startup.cs,我们没有做太多改变,这让它看起来更像旧的 .Net Core 风格。 

我们可以做得更好吗?

    使用Startup.cs确实有助于改善组织,但我认为我们可以做得更好。我一直讨厌文件中Startup.cs单词ConfigureServices()和Configure()彼此太接近,而且你还要传递一个IConfiguration对象。这可能会让人搞不清楚什么放在哪里。

    我们为什么不尝试改进这一点呢?我不喜欢这个名字ConfigureServices()。如果我们将它重命名为RegisterDependentServices()并将其放在自己的文件中会怎么样?这将使我们更容易理解发生了什么。

// RegisterDependentServices.cs file
using Microsoft.AspNetCore.Authentication.JwtBearer;

public static class RegisterDependentServices
{
    public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
    {
        // Register your dependencies
        builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer();
        builder.Services.AddAuthorization();
        return builder;
    }
}

        我决定创建该类static并使用扩展方法将其添加到该类中。我们稍后WebApplicationBuilder会看到这如何改进文件。Program.cs

        接下来,让我们创建一个新文件SetupMiddlewarePipeline.cs。此文件将包含中间件管道。

public static class SetupMiddlewarePipeline
{
    public static WebApplication SetupMiddleware(this WebApplication app)
    {
        // Configure the pipeline !! ORDER MATTERS !!
        app.UseAuthorization();
        app.UseAuthentication();
        app.MapGet("/", () =>
        {
            return "hello world";
        }).RequireAuthorization();
        return app;
    }
}

现在,这会如何改变我们的Program.cs文件? 

// Program.cs file
WebApplication app = WebApplication.CreateBuilder(args)
    .RegisterServices()
    .Build();

app.SetupMiddleware()
    .Run();

这样就生成了一个非常干净的Program.cs文件。事实上,如果您愿意,您可以将其全部放在一行中。

// Program.cs file
WebApplication.CreateBuilder(args)
    .RegisterServices()
    .Build()
    .SetupMiddleware()
    .Run();

我并不讨厌它。事实上,我觉得我喜欢它。

那么 IConfiguration 怎么样?

    之前,Startup()构造函数需要IConfiguration注入其中。但是,由于WebApplication和WebApplicationBuilder都具有.Configuration属性,因此我们不再需要显式注入它。

// RegisterDependentServices.cs file
public static class RegisterDependentServices
{
  public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
  {
    // ******* Access the configuration *******
    var config = builder.Configuration;

    // Register your dependencies
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer();
    builder.Services.AddAuthorization();
    return builder;
  }
}

// setupMiddlewarePipeline.cs file
public static class SetupMiddlewarePipeline
{
  public static WebApplication SetupMiddleware(this WebApplication app)
  {
    // ******** Access the configuration ********
    var config = app.Configuration;

    // Configure the pipeline !! ORDER MATTERS !!
    app.UseAuthorization();
    app.UseAuthentication();
    app.MapGet("/", () =>
    {
      return "hello world";
    }).RequireAuthorization();
    return app;
  }
}

如果我们需要访问应用程序的配置,它是可用的,而且我们的状况很好。 

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/958808.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idea plugin插件开发——入门级教程(IntelliJ IDEA Plugin)

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;idea plugin插件开发——入门级教程&#xff08;IntelliJ IDEA Plugin&#xff09;-CSDN博客 目录 前言 官方 官方文档 代码示例 开发前必读 Intellij、Gradle、JDK 版本关系 plu…

概率密度函数(PDF)分布函数(CDF)——直方图累积直方图——直方图规定化的数学基础

对于连续型随机变量&#xff0c;分布函数&#xff08;Cumulative Distribution Function, CDF&#xff09;是概率密度函数&#xff08;Probability Density Function, PDF&#xff09;的变上限积分&#xff0c;概率密度函数是分布函数的导函数。 如果我们有一个连续型随机变量…

三分钟简单了解一些HTML的标签和语法_02

1.a标签演示 点击然后跳转 代码加入title 2.图片链接 3.锚点链接 点击就会跳转的当前位置 4.a标签小知识补充 该实例会跳转到顶,锚点链接则会跳转到相应的锚点 5. 结果:直接跳转到该页面的锚点处 6. 在 HTML 中&#xff0c;<tr>标签表示表格中的行&#xff08;TableRow&…

mysql 学习3 SQL语句--整体概述。SQL通用语法;DDL创建数据库,查看数据库,删除数据库,使用数据库;

SQL通用语法 SQL语句分类 DDL data definition language : 用来创建数据库&#xff0c;创建表&#xff0c;创建表中的字段&#xff0c;创建索引。因此成为 数据定义语言 DML data manipulation language 有了数据库和表以及字段后&#xff0c;那么我们就需要给这个表中 添加数…

基于ollama,langchain,springboot从零搭建知识库三【解析文档并存储到向量数据库】

安装环境 安装pgvector&#xff0c;先设置docker镜像源&#xff1a; vim /etc/docker/daemon.json {"registry-mirrors": ["https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com","https://mirror.ccs.tencentyun.com",&…

C# OpenCV机器视觉:红外体温检测

在一个骄阳似火的夏日&#xff0c;全球却被一场突如其来的疫情阴霾笼罩。阿强所在的小镇&#xff0c;平日里熙熙攘攘的街道变得冷冷清清&#xff0c;人们戴着口罩&#xff0c;行色匆匆&#xff0c;眼神中满是对病毒的恐惧。阿强作为镇上小有名气的科技达人&#xff0c;看着这一…

计算机视觉算法实战——无人机检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​ 1. 引言✨✨ 随着无人机技术的快速发展&#xff0c;无人机在农业、物流、监控等领域的应用越来越广泛。然而&#xff0c;无人机的滥用也带…

日志收集Day004

1.filebeat安装 基于二进制安装filebeat (1)下载filebeat软件包 (2)解压软件包 tar xf filebeat-7.17.5-linux-x86_64.tar.gz -C /app/softwares/ (3)验证filebeat安装是否成功 cd /app/softwares/filebeat-7.17.5-linux-x86_64/ ln -svf pwd/filebeat /usr/local/sbin/ f…

Vue入门(Vue基本语法、axios、组件、事件分发)

Vue入门 Vue概述 Vue (读音/vju/&#xff0c;类似于view)是一套用于构建用户界面的渐进式框架&#xff0c;发布于2014年2月。与其它大型框架不同的是&#xff0c;Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三…

缓存商品、购物车(day07)

缓存菜品 问题说明 问题说明&#xff1a;用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大。 结果&#xff1a; 系统响应慢、用户体验差 实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询…

数据结构测试题2

一、单选题&#xff08;每题 2 分&#xff0c;共20分&#xff09; 1. 栈和队列的共同特点是( A )。 A.只允许在端点处插入和删除元素 B.都是先进后出 C.都是先进先出 D.没有共同点 2. 用链接方式存储的队列&#xff0c;在进行插入运算时( C ) A. 仅修改头指针 B. 头…

qml Settings详解

1、概述 QML中的Settings类提供了一种便捷的方式来保存和恢复应用程序的配置信息&#xff0c;如用户名、密码、窗口位置和大小等。它简化了配置数据的存储过程&#xff0c;无需使用像SQLite这样的数据库系统。通过使用Settings&#xff0c;开发者可以轻松实现应用程序设置的持…

认识Django项目模版文件——Django学习日志(二)

1.默认文件介绍 └── djangoproject1/├── djangoproject1/│ ├── urls.py [URL和函数的对应关系]【常用文件】│ ├── settings.py [项目配置文件]【常用文件】│ ├── _init_.py│ ├── wsgi.py [接受网络请求] 【不要动】│ └──…

Qt实践:一个简单的丝滑侧滑栏实现

Qt实践&#xff1a;一个简单的丝滑侧滑栏实现 笔者前段时间突然看到了侧滑栏&#xff0c;觉得这个抽屉式的侧滑栏非常的有趣&#xff0c;打算这里首先尝试实现一个简单的丝滑侧滑栏。 首先是上效果图 &#xff08;C&#xff0c;GIF帧率砍到毛都不剩了&#xff09; QProperty…

【Linux网络编程】传输层协议

目录 一&#xff0c;传输层的介绍 二&#xff0c;UDP协议 2-1&#xff0c;UDP的特点 2-2&#xff0c;UDP协议端格式 三&#xff0c;TCP协议 3-1&#xff0c;TCP报文格式 3-2&#xff0c;TCP三次握手 3-3&#xff0c;TCP四次挥手 3-4&#xff0c;滑动窗口 3-5&#xf…

[C]基础8.详解操作符

博客主页&#xff1a;算法歌者本篇专栏&#xff1a;[C]您的支持&#xff0c;是我的创作动力。 文章目录 0、总结1、操作符的分类2、二进制和进制转换2.1、2进制转10进制2.2、10进制转2进制2.3、2进制转8进制和16进制 3、原码、反码、补码4、移位操作符4.1 左移操作符4.2 右移操…

基于Springboot用axiospost请求接收字符串参数为null的解决方案

问题 ​ 今天在用前端 post 请求后端时发现&#xff0c;由于是以 Json对象的形式传输的&#xff0c;后端用两个字符串形参无法获取到对应的参数值 前端代码如下&#xff1a; axios.post(http://localhost:8083/test/postParams,{a: 1, b:2} ,{Content-Type: application/jso…

数据结构——堆(介绍,堆的基本操作、堆排序)

我是一个计算机专业研0的学生卡蒙Camel&#x1f42b;&#x1f42b;&#x1f42b;&#xff08;刚保研&#xff09; 记录每天学习过程&#xff08;主要学习Java、python、人工智能&#xff09;&#xff0c;总结知识点&#xff08;内容来自&#xff1a;自我总结网上借鉴&#xff0…

【Qt】05-菜单栏

做菜单 前言一、创建文件二、菜单栏 QMenuBar2.1 示例代码2.2 运行结果 三、工具栏 QToolBar3.1 运行代码3.2 结果分析 四、状态栏 QStatusBar4.1 运行代码4.2 运行结果 五、文本编辑框 QTextEdit5.1 运行代码5.2 运行结果 六、浮动窗口 addDockWidget6.1 运行代码6.2 运行结果…

【喜讯】海云安荣获“数字安全产业贡献奖”

近日&#xff0c;国内领先的数字化领域独立第三方调研咨询机构数世咨询主办的“2025数字安全市场年度大会”在北京成功举办。在此次大会上&#xff0c;海云安的高敏捷信创白盒产品凭借其在AI大模型技术方面的卓越贡献和突出的技术创新能力&#xff0c;荣获了“数字安全产业贡献…