首页后端开发ASP.NETasp.net core入门之Startup

asp.net core入门之Startup

时间2023-11-27 17:18:03发布访客分类ASP.NET浏览790
导读:Startup介绍#Startup是Asp.net Core的应用启动入口。在.NET5及之前一般会使用startup.cs类进行程序初始化构造。如下: public class Startup { public Startup(I...

Startup介绍#

Startup是Asp.net Core的应用启动入口。在.NET5及之前一般会使用startup.cs类进行程序初始化构造。如下:


public class Startup
{

    public Startup(IConfiguration configuration)
    {
    
        Configuration = configuration;

    }


    public IConfiguration Configuration {
     get;
 }


    public void ConfigureServices(IServiceCollection services)
    {
    
        services.AddRazorPages();

    }


    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

        if (env.IsDevelopment())
        {
    
            app.UseDeveloperExceptionPage();

        }

        else
        {
    
            app.UseExceptionHandler("/Error");
    
            app.UseHsts();

        }
    

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

        app.UseRouting();
    

        app.UseAuthorization();
    

        app.UseEndpoints(endpoints =>

        {
    
            endpoints.MapRazorPages();

        }
    );

    }

}

并在Program中使用IHostBuilder构造Host程序:


public class Program
{

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

    }
    

    public static IHostBuilder CreateHostBuilder(string[] args) =>
    
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>

            {
    
                webBuilder.UseStartupStartup>
    ();

            }
    );

}
    

在.NET5之后的版本中,简化了这一操作(当然也可以继续保留这种方式),我们可以直接在Program的程序入口Main函数中直接构造配置我们的Startup,或者直接使用顶级语句的方式,在Program类中直接编写。


var builder = WebApplication.CreateBuilder(args);
    

// Add services to the container.
builder.Services.AddRazorPages();
    
builder.Services.AddControllersWithViews();
    

var app = builder.Build();


// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    
    app.UseExceptionHandler("/Error");
    
    app.UseHsts();

}
    

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

app.UseAuthorization();
    

app.MapGet("/hi", () =>
     "Hello!");
    

app.MapDefaultControllerRoute();
    
app.MapRazorPages();
    

app.Run();
    

对比之下,很容易发现,其中在var app = builder.Build(); 之前的代码这是做我们应用的初始化,比如依赖注入,配置加载等等操作,相当于Startup.cs中的ConfigureServices方法。 对应的,下面的操作就是我们的中间件配置,对应Startup.cs中的Configure方法。 同时我们可以发现,在新版的中间件配置中,少了UseRouting和UseEndpoints用来注册路由的中间件,是因为使用最小托管模型时,终结点路由中间件会包装整个中间件管道,因此无需显式调用 UseRouting 或 UseEndpoints 来注册路由。UseRouting 仍可用于指定进行路由匹配的位置,但如果应在中间件管道开头匹配路由,则无需显式调用 UseRouting。 app.MapRazorPages(); 就相当于 app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); } );

扩展Startup#

在asp.net core中有一个IStartupFilter的接口,用于扩展Startup。 IStartupFilter 在不显式注册默认中间件的情况下将默认值添加到管道的开头。 IStartupFilter 实现 Configure,即接收并返回 Action。IApplicationBuilder 定义用于配置应用请求管道的类。 每个 IStartupFilter 可以在请求管道中添加一个或多个中间件。筛选器按照添加到服务容器的顺序调用。筛选器可在将控件传递给下一个筛选器之前或之后添加中间件,从而附加到应用管道的开头或末尾。 我们来实践一下,首先创建一个空的asp.net core模板很简单,只有一个Program文件。

再来添加一个IStartupFilter的实现,只用于控制台输出执行内容。


using Microsoft.AspNetCore.Hosting;


namespace LearnStartup
{

    public class StartupFilterOne : IStartupFilter
    {
    
        public ActionIApplicationBuilder>
     Configure(ActionIApplicationBuilder>
 next)
        {
    
            return builder =>
 
            {
    
                builder.Use(async (httpContext, _next) =>
 
                {
    
                    Console.WriteLine("-----StartupFilterOne-----");
    
                    await _next(httpContext);

                }
    );
    
                next(builder);

            }
    ;

        }

    }

}
    

在Program中添加一行代码注册StartupFilterOne


using LearnStartup;
    

var builder = WebApplication.CreateBuilder(args);
    

builder.Services.AddTransientIStartupFilter, StartupFilterOne>
    ();
     //注入StartupFilterOne

var app = builder.Build();
    

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

app.Run();
    

启动程序,可以看到如下结果,中间件正常执行:

当我们有多个IStartupFilter时,我们怎么控制中间件执行顺序呢?上面所说,跟我们注入的顺序有关。 新增一个StartupFilterTwo,在修改一下Program


using LearnStartup;
    

var builder = WebApplication.CreateBuilder(args);
    

builder.Services.AddTransientIStartupFilter, StartupFilterTwo>
    ();
    
builder.Services.AddTransientIStartupFilter, StartupFilterOne>
    ();
    

var app = builder.Build();
    

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

app.Run();

可以看到是先执行StartupFilterTwo中的中间件,然后再执行StartupFilterOne的中间件。

以上写法都是把中间件注册在中间件管道头部,那么如何让他在尾部执行呢? 在IStartupFilter.Configure(Action next)中的参数next,本质其实就是Startup中的Configure(感兴趣可以翻源码查看),只要调整next的执行顺序即可。 我们调整一下StartupFilterTwo的代码


public class StartupFilterTwo : IStartupFilter
    {
    
        public ActionIApplicationBuilder>
     Configure(ActionIApplicationBuilder>
 next)
        {
    
            return builder =>

            {
    
                next(builder);
    
                builder.Use(async (httpContext, _next) =>
 
                {
    
                    Console.WriteLine("-----StartupFilterTwo-----");
    
                    await _next(httpContext);

                }
    );

            }
    ;

        }

    }
    

将next(builder)放在前面执行,我们来看看效果

此时,发现我们StartupFilterTwo并没有执行,那是因为app.MapGet("/", () => "Hello World!"); 是一个终结点中间件,而StartupFilterTwo注册到了中间件末尾,执行到这个中间件时就直接返回没有继续执行下一个中间件。 当我们修改Url路径为/test时,没有匹配到HelloWorld的中间件,StartupFilterTwo中的内容成功输出。

浅谈一下IStartupFilter的应用场景#

IStartupFilter可以用于模块化开发的方案,在各自类库中加载对应的中间件。 在请求头部管道做一些请求的校验or数据处理。 在请求管道尾部时,如上图404,无法匹配到路由,我们可以做哪些处理。

注意事项:#

IStartupFilter只能注册在中间件管道头部或者尾部,请确保中间件的使用顺序。 若中间件需要在管道中间插入使用,请使用正常的app.use在startup中正确配置。

IHostingStartup#

可在启动时从应用的 Program.cs 文件之外的外部程序集向应用添加增强功能,比如我们一些0代码侵入的扩展服务,在SkyApm中的.NET实现就是基于这种方式。 我们新建一个StartupHostLib类库,添加一下Microsoft.AspNetCore.Hosting的nuget包 然后新增一个Startup类库实现IHostingStartup。 注意,必须需要添加标记,否则无法识别HostingStartup [assembly: HostingStartup(typeof(LearnStartup.OneHostingStartup))]


using Microsoft.AspNetCore.Hosting;


[assembly: HostingStartup(typeof(LearnStartup.OneHostingStartup))]
namespace StartupHostLib
{


    public class OneHostingStartup : IHostingStartup
    {

        public void Configure(IWebHostBuilder builder)
        {
    
            builder.ConfigureAppConfiguration((config) =>
 
            {
    
                Console.WriteLine("ConfigureAppConfiguration");

            }
    );
    

            builder.ConfigureServices(services =>

            {
    

                Console.WriteLine("ConfigureServices");

            }
    );
    

            builder.Configure(app =>

            {
    
                Console.WriteLine("Configure");

            }
    );

        }

    }

}

在LearnStartup中引用项目,并在launchSettings的环境变量中添加 "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "StartupHostLib" 然后启动项目

这里可以发现,HostingStartup的执行顺序是优于应用的。 但是出现一个问题,发现原本的HelloWorld中间件消失了,但是我们依赖注入加载的中间件依旧生效。我们注释builder.Configure方法之后再启动程序。


public void Configure(IWebHostBuilder builder)
{
    
    builder.ConfigureAppConfiguration((config) =>
 
    {
    
        Console.WriteLine("ConfigureAppConfiguration");

    }
    );
    

    builder.ConfigureServices(services =>

    {
    

        Console.WriteLine("ConfigureServices");

    }
    );
    

    //builder.Configure(app =>

    //{
    
    //    Console.WriteLine("Configure");

    //}
    );

}

可以发现,应用中间件正常了。说明HostingStartup中配置中间件和应用的中间件配置冲突,并覆盖应用中间件。 我们将StartupFilterOne和StartupFilterTwo放到OneHostingStartup中去配置依赖注入,再次启动项目观察。


public void Configure(IWebHostBuilder builder)
{
    
    builder.ConfigureAppConfiguration((config) =>
 
    {
    
        Console.WriteLine("ConfigureAppConfiguration");

    }
    );
    
    builder.ConfigureServices(services =>

    {
    
        services.AddTransientIStartupFilter, StartupFilterTwo>
    ();
    
        services.AddTransientIStartupFilter, StartupFilterOne>
    ();
    
        Console.WriteLine("ConfigureServices");

    }
    );
    

    //builder.Configure(app =>

    //{
    
    //    Console.WriteLine("Configure");

    //}
    );

}
    

可以发现,依赖注入中加载的中间件是生效的。

浅谈IHostingStartup应用场景#

由上面表现可以发现 IHostingStartup执行顺序由于应用执行顺序。 IHostingStartup中配置中间件管道会覆盖应用中间件管道。 依赖注入中IStartupFilter配置中间件可以正常使用不覆盖应用中间件。 所以我们使用HostingStartup的场景可以为: 对代码0侵入的场景,比如AOP数据收集(如SkyApm)。 没有中间件的场景OR符合IStartupFilter中间件的场景。 想深入了解的可以自行翻看源码,本文浅尝即止。

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: asp.net core入门之Startup
本文地址: https://pptw.com/jishu/557841.html
ASP.NET MVC基于WebUploader大文件分片上传、断网续传、秒传 ASP.NET Core 使用最简洁的代码实现登录、认证和注销

游客 回复需填写必要信息