ASP.NET Core 中的应用启动

一题多解,ASP.NET Core应用启动初始化的N种方案[上篇] ASP.NET Core应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来。在ASP.NET Core的发展历史上先后出现了三种应用承载的编程方式,而且后一种编程模式都提供了针对之前编程模式的全部或者部分兼容,这就导致了一种现象:相同的更能具有N种实现方式。对这个发展历程不是特别了解的读者会有很多疑问?为什么这么多不同的编程模式都在作同一件事?它们之间的有什么差别之处?为什么有的API在最新的Minimal API又不能用了呢?[本文部分内容来 阅读详情

ASP.NET Core 中的应用启动

启动类用于配置服务和应用程序的请求管道。

Startup类

在ASP.NET Core中,按照约定将启动类命名Startup,Startup类必须包括Configure方法,该方法用于创建应用的请求处理管道。除了Configure方法外,Startup类也可以包括ConfigureServices方法,但不是必须的,ConfigureServices方法用于配置应用的服务。

Startup类最终在Program.cs中被引入。

当创建一个Empty的Web应用程序时,Startup类中默认包含的代码如下:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    }
}

上述代码中,并没有显式的指定Startup构造函数,如果你想要使用常见的一些服务,比如配置服务、日志记录服务等,可以在Startup构造函数中显式的指定,这些是Web主机提供给Startup类构造函数可用的服务,常见的有:

  • IHostingEnvironment 以按环境配置服务。
  • IConfiguration 以读取配置。
  • ILoggerFactory 以在 Startup.ConfigureServices 中创建记录器。

除了这些服务之外,应用还可以通过ConfigureServices方法添加其他服务,然后,主机和应用服务都可以在Configure和整个应用中使用。

改写后的代码如下:

public class Startup
{
    private readonly IHostingEnvironment _env;
    private readonly IConfiguration _config;
    private readonly ILoggerFactory _loggerFactory;

    public Startup(IHostingEnvironment env, IConfiguration configuration, ILoggerFactory loggerFactory)
    {
        _env = env;
        _config = configuration;
        _loggerFactory = loggerFactory;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        ILogger<Startup> logger = _loggerFactory.CreateLogger<Startup>();
        if (_env.IsDevelopment())
        {
            logger.LogInformation("当前是开发环境");
        }
        else
        {
            logger.LogInformation($"环境名称:{_env.EnvironmentName}");
        }
        //可以在此处直接访问_config
    }

    public void Configure(IApplicationBuilder app)
    {
        if (_env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    }
}

ConfigureServices方法

ConfigureServices方法是可选的,它在Configure方法配置应用程序之前,由Web主机调用,用于设置配置选项。

该方法中,典型模式是先调用所有的services.Add{Service}方法,然后再调用所有的services.Configure{Service} 方法。虽然并不是所有的都遵循该模式,但是一般而言,都至少会调用这两个形式的方法,只是先后顺序不一样。例如,在使用VS2017创建ASP.NET Core MVC应用程序时,ConfigureServices方法包含的代码如下:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

ConfigureServices方法将服务添加到服务容器,使其能够在应用中(通过依赖关系注入解析)和Configure 方法中(通过IApplicationBuilder.ApplicationServices解析)可用。

注意:并不是所有的服务都会在ConfigureServices方法中配置,Web主机可能会在调用 Startup 方法之前配置某些服务。

ConfigureServices方法提供了IServiceCollection参数,IServiceCollection提供了Add[Service] 扩展方法,可以支持大量设置的功能,常见的如实体框架、身份标识和MVC等:

public void ConfigureServices(IServiceCollection services)
{
    // 添加实体框架服务.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    // 添加身份服务
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();
    // 添加MVC的支持
    services.AddMvc();

    // 添加其他的应用程序服务
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

Configure方法

Configure方法用于指定应用程序如何响应HTTP请求。请求管道是通过向IApplicationBuilder实例添加中间件组件来配置的。Configure方法可以使用IApplicationBuilder,但它不在服务容器中注册。托管负责创建IApplicationBuilder,并将其直接传递给Configure方法。

下面是创建MVC应用程序默认生成的代码:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

每个Use扩展方法都向请求管道添加一个中间件组件。例如,UseMvc扩展方法将路由中间件添加到请求管道中,并将MVC配置为默认处理程序。

请求管道中的每个中间件组件负责调用管道中的下一个组件,或者在适当的情况下使链短路。如果在中间件链中没有发生短路,那么每个中间件都有第二次机会在将请求发送到客户端之前处理该请求。

其他服务,如IHostingEnvironment和ILoggerFactory,也可以在方法签名中指定。如果指定了这些服务,一旦可用,就会被注入。

不使用Startup类

可以使用ConfigureServices和Configure便利方法来代替指定启动类。 多次调用 ConfigureServices 将追加到上一个。 多次调用 Configure 将使用上一个方法调用(注:这里描述不够准确,需要实际验证,强烈建议只调用一次Configure方法)。

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Docs.AppStartup
{
    public class Program
    {
        public static IHostingEnvironment HostingEnvironment { get; set; }
        public static IConfiguration Configuration { get; set; }

        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                HostingEnvironment = hostingContext.HostingEnvironment;
                Configuration = config.Build();
            })
            .ConfigureServices(services =>
            {
                services.AddMvc();
            })
            .Configure(app =>
            {
                ILoggerFactory loggerFactory = app.ApplicationServices.GetRequiredService<ILoggerFactory>();
                ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
                logger.LogInformation("Logged in Configure");

                if (HostingEnvironment.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                }

                //可以在此处访问Configuration
                app.UseMvcWithDefaultRoute();
                app.UseStaticFiles();
            });
        }
    }
}

使用Startup过滤器扩展Startup

可以使用IStartupFilter在应用程序的Configure中间件管道的开头或结尾配置中间件。在应用程序请求处理管道的开始或结束时,IStartupFilter有助于确保中间件在由库添加的中间件之前或之后运行。

IStartupFilter实现了单个方法Configure,该方法接收并返回一个Action<IApplicationBuilder>。IApplicationBuilder定义用于配置应用程序请求管道的类。

IStartupFilter定义如下:

namespace Microsoft.AspNetCore.Hosting
{
	public interface IStartupFilter
	{
		Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
	}
}

每个IStartupFilter在请求管道中实现一个或多个中间件。过滤器是按照添加到服务容器的顺序调用的。过滤器可以在向下一个过滤器传递控制之前或之后添加中间件,从而附加到应用程序管道的开头或结尾。

下述代码自定义一个过滤器,实现IStartupFilter:

public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder => {
        	//向IStartupFilter注册中间件
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}

其中RequestSetOptionsMiddleware的代码如下,它包含一个中间件,该中间件通过查询字符串参数设置选项值:

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;
    private IOptions<AppOptions> _injectedOptions;

    public RequestSetOptionsMiddleware(
        RequestDelegate next, IOptions<AppOptions> injectedOptions)
    {
        _next = next;
        _injectedOptions = injectedOptions;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        Console.WriteLine("RequestSetOptionsMiddleware.Invoke");

        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            _injectedOptions.Value.Option = System.Net.WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

上述代码中的IOptions<AppOptions>是为了通过依赖注入,基于IOptions直接在构造函数中得到Appoptions的实例,injectedOptions包含的AppOptions是已经被实例化的,这样就可以直接在后面使用。AppOptions的定义如下,IOptions的作用是为了引入依赖注入:

public class AppOptions
{
    public string Option { get; set; } = "Option Default Value";
}

最后,在 IWebHostBuilder.ConfigureServices 中的服务容器中注册IStartupFilter:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .ConfigureServices(service => {
        service.AddTransient<IStartupFilter, RequestSetOptionsStartupFilter>();
    })
    .UseStartup<Startup>();

运行上述代码,如果添加断点将会看到,当提供 option 的查询字符串参数时,中间件在 MVC 中间件呈现响应之前处理分配值。

中间件执行顺序由IStartupFilter注册的顺序设置:

  • 多个IStartupFilter实现可能与相同的对象进行交互。如果排序很重要,请将它们的 IStartupFilter 服务注册进行排序,以匹配其中间件应有的运行顺序。
  • 库可能添加包含一个或多个 IStartupFilter 实现的中间件,这些实现在向 IStartupFilter 注册的其他应用中间件之前或之后运行。 若要在库的 IStartupFilter 添加中间件之前调用 IStartupFilter 中间件,请在将库添加到服务容器之前定位服务注册。 若要在此后调用,请在添加库之后定位服务注册。

https://github.com/octocean26/Dazzle-DotNETCore/blob/73a646523287d3dffa93a42c0eb5cab4722ff2ef/notes/Docs/ASP.NET%20Core%20%E5%BA%94%E7%94%A8%E5%90%AF%E5%8A%A8.md

如何启动 .NET Core 项目 首先,您需要在您的计算机上安装 .NET Core SDK。通过按照上述步骤,您可以成功启动 .NET Core 项目。请注意,您可以使用其他工具和功能来管理和扩展 .NET Core 项目,例如使用 NuGet 包管理器添加依赖项、使用 ASP.NET Core 构建 Web 应用程序等。一旦您安装了 .NET Core SDK,您可以使用命令行界面(CLI)或集成开发环境(IDE)创建 .NET Core 项目。在创建项目后,您可以使用您喜欢的文本编辑器打开项目文件夹,并编辑项目文件。 阅读详情

相关推荐

vmware vsphere5---部署vCSA(VMware vCenter Server)附带第二阶段安装报错解决方案

因为这份文档我是边做边写的,遇到问题重新装了好几次所以IP会很乱ESXI主机为192.168.20.10VCSA为192.168.20.7,后台为192.168.20.7:5480后期请自行对应,后面的192.168.20.57请对应192.168.20.7,或根据自己的来。

m0_70212665的博客 5710

详细分析asp.net core启动流程

ASP.NET Core 启动流程可以分为以下几个步骤:加载主机配置文件 ASP.NET Core 应用程序启动时,首先会加载主机配置文件。主机配置文件是一个 JSON 格式的文件,包含了应用程序的配置信息,例如端口号、环境变量、日志级别等。创建主机 接下来,应用程序会使用主机配置文件中的信息创建一个主机。主机是一个基于 HTTP 的服务器,它负责监听客户端请求并将请求转发给 ASP.NET Co...

dotNET跨平台 752

LTE信令流程及业务流程

eNB返回E-RAB建立响应消息,E-RAB建立列表信息中包含成功建立的承载信息,E-RAB建立失败列表消息中包含没有成功建立的承载消息。3)当下行数据达到时,网络侧先对UE进行寻呼,随后UE发起随机接入过程,并发起service request过程。用户面:S-GW向eNB发送承载建立请求,包含(IMSI, QoS, TFT, TEID, LBI等)控制面:MME向eNB发送E-RAB建立请求,包含E-RAB ID,QoS,S-GW TEID。3)在S1接口上建立S1承载,在Uu接口上建立数据无线承载。

qq_44390640的博客 4581

使用cmd命令行启动asp.net core 以及.net 5项目

asp.net core 通过CMD命令启动

qq_34550459的博客 1826

Mac用户必看:PD虚拟机网络初始化失败的3分钟修复指南(附详细截图)

本文针对Mac用户在Parallels Desktop(PD虚拟机)启动时遇到的“网络初始化失败”问题,提供了快速诊断与修复指南。核心原因是macOS系统更新后权限未正确授予。文章通过详细的三步修复法(关闭进程、修改配置文件、重新授权重启),帮助用户在3分钟内恢复虚拟机网络连接,并附有排查清单与预防建议。

weixin_29231027的博客 534

Python环境搭建和LabVIEW中的调用

本文主要介绍Python相关的环境搭建、Anaconda的使用以及在LabVIEW中调用Python的方法。

lvxisi的博客 6389

asp.net core入门之Startup

转自:饭勺oOcnblogs.com/fanshaoO/p/17577568.htmlStartup介绍#Startup是Asp.net Core的应用启动入口。在.NET5及之前一般会使用startup.cs类进行程序初始化构造。如下:public class Startup { public Startup(IConfiguration configuration) { ...

weixin_68436326的博客 709

(10)Proteus 8.9上的STM32仿真系列(HAL)---freertos

实验设计:通过cubemxide生成freertos工程,然后创建一个 pc13 led灯间隔200ms闪烁的任务。非常遗憾的是proteus8.9仿真失败,实物上没有问题,但还是把流程过一遍。 一、原理图 实物是淘宝上stm32f103 c8t6的核心板,proteus上没有这个芯片,这里图上大概表示一下,用的是核心板自带的pc13引脚的led灯。 二、cubemxide配置 1.RCC如之前工程一样配置 2、配置SYS timebase Source不要使用systick,自己选择一个定时器,我这

qq_35442550的博客 7342

一张图理清ASP.NET Core启动流程

1. 引言 对于ASP.NET Core应用程序来说,我们要记住非常重要的一点是:其本质上是一个独立的控制台应用,它并不是必需在IIS内部托管且并不需要IIS来启动运行(而这正是ASP.NET Core跨平台的基石)。ASP.NET Core应用程序拥有一个内置的Self-Hosted(自托管)的Web Server(Web服务器),用来处理外部请求。 不管是托管还是自托管,都离不开H

dotNET跨平台 3083

【无标题】STM32F767串口空闲中断+DMA实现不定帧长度的接收

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、配置串口与DMA二、空闲中断服务函数二.串口+DMA发送三、主函数总结 前言 提示:这里可以添加本文要记录的大概内容: 使用STM32F767实现串口空闲中断+DMA传输接收不定帧长度数据,以及当中可能遇到的错误总结 提示:以下是本篇文章正文内容,下面案例可供参考 一、配置串口与DMA //硬件模块配置可直接通过CUBEMX配置 void MX_USART1_UART_Init(void) { huart1.In.

qq_42589531的博客 1167

AI 生成 ECU 功能测试用例

本文分享了AI辅助汽车电子测试的实战经验。作者以某车企车身控制器(BCM)项目为例,对比了传统测试用例编写方式(需100小时)与AI辅助方式(仅3个工作日)的效率差异,实现76%的效率提升。文章详细展示了从需求文档生成测试用例的全过程,包括需求文档示例、AI提示词模板和AI生成的完整测试用例表格(涵盖正常功能、边界条件、异常场景等测试类型)。通过具体案例说明如何利用AI快速生成初稿后人工审核优化的方法,为ECU测试工程师提供了可复用的效率提升方案。

小明的博客 877

ASP.NET Core的应用启动

Startup类 startUp类是应用程序的入口,这个类可以设置配置,并且将应用程序将要使用的服务连接起来。开发人员可以在startup类中配置请求管道,该管道将用于处理应用程序的所有请求。 Configure方法 用于指定ASP.NET应用程序如何响应每一个HTTP请求。 ConfigureService方法 可以在IServiceCollection上使用扩展方法来包装乣大量配置细节的Con...

charly 361

Rclone替代RaiDrive?零广告免费挂载Alist WebDAV到Windows资源管理器(含自启脚本)

本文详细介绍了如何使用开源工具Rclone替代RaiDrive,实现零广告、全免费的Alist WebDAV挂载方案。通过深入解析配置参数、提供完整的自启动解决方案和解决常见问题,帮助用户在Windows资源管理器中高效管理云存储,提升使用体验。

weixin_33709364的博客 631

Asp.Net Core应用启动Startup类简介

  1.前言      Core与早期版本的 ASP.NET 对比,配置应用程序的方式的 Global.asax、FilterConfig.cs和RouteConfig.cs 都被Program.cs 和 Startup.cs取代了。Program.cs作为Web应用程序的默认入口,在没有任何修改的情况下,会调用同目录下Startup.cs中的ConfigureServices 和 Configu...

li123128的博客 1354

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

(1)ASP.NET Core 应用启动Startup类简介

1.前言 Core与早期版本的 ASP.NET 对比,配置应用程序的方式的 Global.asax、FilterConfig.cs和RouteConfig.cs 都被Program.cs 和 Startup.cs取代了。Program.cs作为Web应用程序的默认入口,在没有任何修改的情况下,会调用同目录下Startup.cs中的ConfigureServices 和 Configure方法。 ...

weixin_30849591的博客 444

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ASP.NET Core 应用程序启动

启动流程 创建并默认配置HostBuilder对象,用来构建Host的对象。 HostBuilder对象配置参数,包括注册的服务,组件,请求处理管道相关内容(Startup 类 配置服务和应用的请求管道),增加了ASP.NET Core的运行时设置。 配置好的HostBuilder对象构建Host对象。 Host对象启动.Run()。 控制台成为ASP.NET Core的web应用程序,开始监听请求。 Host监听到请求后,请求需要经过Host配置的请求处理管道进行相关处理。 什么是Host Host

随笔 704

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

ASP.NET Core 应用程序启动机制 宿主概念

在 ASP.NET Core 中,宿主(Host)是应用程序的运行环境容器启动和初始化整个应用管理应用的生命周期(启动、运行、关闭)提供依赖注入(DI)容器配置服务(如日志、配置、中间件等)托管 Web 服务器(如 Kestrel)宿主 = 应用程序的“操作系统”,它让应用能跑起来,并提供运行所需的一切基础设施。“当 ASP.NET Core 应用程序启动时,首先会配置并创建宿主(Host)类型,然后运行宿主。宿主用来启动、初始化应用程序,并管理其生命周期。配置宿主:通过。

qq_44967213的博客 1520

在 ASP.NET Core 应用程序启动时运行代码的 3 种方法

在应用程序开始服务Web请求之前,所有类型的启动任务都可以直接从Program或Startup类执行。长时间运行的后台任务应该由托管服务启动和停止。开发者可以使用接口订阅OnStarted事件,该事件在应用宿主完全配置并启动后发布。...

极客神殿 4372

ASP.NET Core主机配置:应用启动与生命周期

ASP.NET Core的主机(Host)系统是现代Web应用程序的核心基础设施,它负责管理应用程序的启动、配置、依赖注入和生命周期。与传统的ASP.NET不同,ASP.NET Core采用了更加灵活和模块化的主机架构,为开发者提供了前所未有的控制能力。 本文将深入探讨ASP.NET Core的主机配置机制、启动流程以及完整的生命周期管理,帮助开发者构建更加健壮和可维护的Web应用程序。 ##...

gitblog_00622的博客 1104

ASP.NET Core 中的应用程序启动 Startup

ASP.NET Core 应用使用Startup类来作为启动类。   Startup类中包含了ConfigureServices方法,Configure方法,IConfiguration,IHostingEnvironment,IServiceCollection,Startup 筛选器   1. IConfiguration 用于获取配置文件 Configur...

weixin_30607659的博客 353

ASP.NET Core 2.0系列学习笔记-应用程序启动

ASP.NET Core应用是一个在Main方法中创建的一个Web服务器的控制台应用程序。默认如下:using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace NETCoreAPI { public class Program { public stati...

ChaITSimpleLove的博客 505

Asp.Net Core 应用程序启动(翻译)

Startup 用于配置服务和应用的请求管道。 The Startup class Asp.Net Core 应用使用StartUp类。StartUp类: 1、可以选择性的包含ConfigureServices方法配置应用的服务。 2、必须包含一个Configure方法,创建应用的请求处理管道。 ConfigureServices和Configure 方法在应用启...

ai6688的博客 237

ASP.NET Core 应用程序的启动与配置:Program.cs 文件的全面解析

Program.cs配置应用程序的主机和服务,包括加载配置、设置日志记录、启用监控(如 Application Insights)、配置 API 版本控制和 Swagger 文档。构建 HTTP 请求管道,配置中间件以处理请求、路由、授权和异常处理。启动应用程序,使其开始监听和处理 HTTP 请求。通过这些步骤,Program.cs确保了应用程序的正确初始化和运行,提供了良好的开发和生产环境支持。

听我俩天的博客 2369
上一篇: C# 使用Emit深克隆
下一篇: System.Data.DbType与各类数据库的数据类型的映射关系
.NET跨平台
博客等级 码龄15年 6066粉丝 738原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值