.NET Core学习

一、初识.NET Core

什么是.NET Core?
开源通用的开发框架,支持跨平台,部署,开发,物联网,云服务。
开发目标:跨平台的.NET应用,包含了.NET Framework的类库(3.0之前,有很多类库是移植的,之后就不在从.NET FW移植。)
.NET Core采用模块化的管理方式,需要什么组件就获取什么组件。

.NET Core特性—
跨平台、跨架构(x86\x64\ARM)、支持命令行、部署灵活、兼容性强(向下)、开源。

.NET Core和.NET Freamework的关系

  1. 从出生角度:
    在这里插入图片描述
  2. 从发展角度:
    .NET Core是.NET FW的下一代产品。

二、ASP.NET Core 3.1

注意:.NET Core 3.1只能运行在VS2019 16.4版本!

ASP.NET Core是重新设计的ASP.NET,从底层将体系结构都改变了。

新功能:Blazor,GRPC(高性能远程过程调用框架)

2.1、启动流程

(1)在VS2019新建一个ASP.NET Core的空web项目。创建完如图:
在这里插入图片描述

文件介绍:
launchSettings.json是项目调试配置文件,对应项目-属性-调试选项卡的配置项。
在这里插入图片描述
appsettings.json是项目配置文件,类似于ASP.NET中的web.config文件。


Program.cs文件,包含了Main方法,web应用的入口方法,主要就是创建主机生成器-配置主机-创建主机-运行主机。


Startup.cs文件,web应用的启动类。

ASP.NET Core Web应用启动步骤:
创建主机生成器>配置主机>创建主机>运行主机在这里插入图片描述

public class Program
    {
        public static void Main(string[] args)
        {
        	//创建主机生成器,然后调用创建主机的方法,然后运行主机
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
        	//调用Host静态类的方法,创建默认的主机生成器,返回一个IHostBuilder的接口
        	//默认配置:加载环境变量、加载命令行参数(命令行启动方式)、加载应用配置、配置的默认日志组件.....
            Host.CreateDefaultBuilder(args)
                //调用扩展方法,进行自定义的配置
                //默认的配置,启用kestrel
                .ConfigureWebHostDefaults(webBuilder =>
                {
                 //指定启动类
                    webBuilder.UseStartup<Startup>();
                });
    }

解释如上代码中的主机:主机负责web应用程序的启动和生成期的管理,配置服务器和请求处理管道。
主机实际上是一个封装了应用资源的对象
在这里插入图片描述
Kestrel:跨平台的适用于ASP.NET Core的web服务器,担当的角色类似于IIS,在linux下性能更高。简单的说,性能高,但功能少,不支持反向代理。
在这里插入图片描述

(2)启动方式分两种,第一种同ASP.NET的IIS启动方式,第二种采用自宿主的方式启动,这里采用自宿主的方式启动。
在这里插入图片描述
启动效果如图:
在这里插入图片描述

2.2、主机与主机配置项

主机配置的方式(按优先级):

  1. 命令行
  2. 应用配置
  3. 硬编码
  4. 环境变量

2.3、注册服务

// 配置WEB应用所需要的服务和中间件
    public class Startup
    {
        // 可选的
        // 注册服务
        public void ConfigureServices(IServiceCollection services)
        {
            // 服务容器 IoC(控制反转,Inversion of Control)容器
            // 注册类型、请求实例

            // 默认已经为我们注册了一些服务,服务,服务容器

            // 添加对控制器和API相关功能的支持,但是不支持视图和页面
            // 你这里是不关心生存期,你不关心有什么配置
            services.AddControllers();

            // 添加对控制器\API\视图相关功能的支持。
            // ASP.NET CORE 3.X MVC模板默认使用
            services.AddControllersWithViews();
            // 添加对Razor Pages和最小控制器的支持
            services.AddRazorPages();

            // 这里是ASP.NET CORE 2.X 
            services.AddMvc();
            services.AddCors();
            // 比较规范的服务封装
            services.AddMessage(builder => builder.UseSms());

            // 内置的服务

            // 第三方的,EF Core,日志框架、Swagger、

            // 注册自定义服务
            // 服务生存期   类型生命周期

            // 注册自定义服务的时候,必须要选择一个生存周期

            // 有几种生存周期
            // 瞬时,每次从服务容器里进行请求实例时,都会创建一个新的实例。
            // 作用域,线程单例,在同一个线程(请求)里,只实例化一次
            // 单例,全局单例,每一次都是使用相同的实例,

//            services.AddSingleton();
//            services.AddTransient();
//            services.AddScoped();

            services.AddSingleton<IMessageService, EmailService>();
            services.AddSingleton<IMessageService, SmsService>();
            // 你这个服务,到底应该是什么生存期?你这个服务要不要配置?
            // 自带不好用,你是可以换成第三方的
        }

        // 配置中间件,中间件组成管道
        // 必须的,中间件使用、自定义中间、管道的原理、就是处理HTTP请求和响应的这么个东西
        // 注入进来的,看一下管道的源码,带着大家模拟实现管道
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IMessageService messageService)
        {
            messageService.Send();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {

                    await context.Response.WriteAsync(messageService.Send());
                });
            });
        }
    }
public interface IMessageService
    {
        string Send();
    }
    public class SmsService : IMessageService
    {
        public string Send()
        {
            return "Sms";
        }
    }
    public class EmailService : IMessageService
    {
        public string Send()
        {
            return "Email";
        }
    }
    
public static class MessageServiceExtension
    {
        public static void AddMessage(this IServiceCollection services, Action<MessageServiceBuilder> configure)
        {
//            services.AddSingleton<IMessageService, EmailService>();

            var builder = new MessageServiceBuilder(services);
            configure(builder);
        }

    }
    public class MessageServiceBuilder
    {
        public IServiceCollection ServiceCollection { get; set; }

        public MessageServiceBuilder(IServiceCollection services)
        {
            ServiceCollection = services;
        }

        public void UseEmail()
        {
            ServiceCollection.AddSingleton<IMessageService, EmailService>();
        }

        public void UseSms()
        {
            ServiceCollection.AddSingleton<IMessageService, SmsService>();
        }
    }

2.4、中间件

中间件的职责:

  1. 选择是否将请求传递给管道中的下一个中间件。
  2. 在管道中的下一个中间件的前后执行工作。

每一个中间件都有权做出决定是否将请求传递给下一个中间件,也可以直接做出响应,促使管道短路。
在这里插入图片描述

ASP.NET Core 路由、认证、会话、缓存,都是由管道来处理的,中间件。
MVC、Web API都是建立在某个特殊的中间件上。

示例代码

 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.UseStartup<Startup>();
                });
    }
public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // 配置中间件
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

            // 封装起来,添加进来
            //use方法,是有next的
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Middleware 1 Begin \r\n");
                await next();
                await context.Response.WriteAsync("Middleware 1 End \r\n");
            });

            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Middleware 2 Begin \r\n");
                await next();
                await context.Response.WriteAsync("Middleware 2 End \r\n");
            });
   
            // run方法,是没有next的,终端中间件
            // 专门用来短路请求管道,是放在最后面的,兜底的。
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello Run \r\n");
            });
            // 大家有没有看过ASP.NET Core的源代码?1,2,知道怎么看吗?

            
            // 环境名称Development
            if (env.IsDevelopment())
            {
                // 开发人员异常页面中间件
                app.UseDeveloperExceptionPage();
            }

            // 终结点(端点)路由中间件

            // ASP.NET CORE 2.X里, 是没这个东西
            // ASP.NET CORE 3.X里  拆出来,都有对路由的需求,所以路由拆出来,为了复用!
            app.UseRouting();

            // 通用的添加中间件的方法
            app.UseMiddleware<TestMiddleware>();
            app.UseTest();
            // 还可以添加一些其它的中间件,

            // 终结点中间件,这里是配置,配置中间件和路由的之间关系,映射
            // 终结点你可以简单理解为 MVC, /控制器/action
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
public static class CustonMiddlewareExtensions
    {
        public static IApplicationBuilder UseTest(this IApplicationBuilder app)
        {
            return app.UseMiddleware<TestMiddleware>();
        }
    }
public class TestMiddleware
    {
        private readonly RequestDelegate _next;
        public TestMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext httpContext)
        {
            // 在这里写中间件的业务代码!!
            // HTTP请求部分的处理
            await _next(httpContext);
            // HTTP响应部分的处理
        }
    }

运行结果:
在这里插入图片描述

2.5、模拟管道模型

public delegate Task RequestDelegate(HttpContext context);

    class Program
    {
        static void Main(string[] args)
        {
            var app = new ApplicationBuilder();

            app.Use(async (HttpContext context,Func<Task> next) =>
            {
                Console.WriteLine("中间件1号 Begin");
                await next();
                Console.WriteLine("中间件1号 End");
            });

            app.Use(async (HttpContext context, Func<Task> next) =>
            {
                Console.WriteLine("中间件2号 Begin");
                await next();
                Console.WriteLine("中间件2号 End");
            });

            // 这时候管道已经形成,执行第一个中间件,就会依次调用下一个
            // 主机创建以后运行的
            var firstMiddleware = app.Build();

            // 当请求进来的时候,就会执行第一个中间件
            // 主机给的
            firstMiddleware(new HttpContext());
        }
    }
public class ApplicationBuilder
    {
        // 中间件,独立的!互相没有关联的,只有一个顺序
        private static readonly IList<Func<RequestDelegate, RequestDelegate>> _components = 
            new List<Func<RequestDelegate, RequestDelegate>>();

        // 扩展Use
        public ApplicationBuilder Use(Func<HttpContext, Func<Task>, Task> middleware)
        {
            return Use(next =>
            {
                return context =>
                {
                    Task SimpleNext() => next(context);
                    return middleware(context, SimpleNext );
                };
            });
        }

        // 原始Use
        public ApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
        {
            // 添加中间件
            _components.Add(middleware);
            return this;
        }
	
        public RequestDelegate Build()
        {
            RequestDelegate app = context =>
            {
                Console.WriteLine("默认中间件");
                return Task.CompletedTask;
            };

            // 上面的代码是一个默认的中间件
            // 重要的是下面几句,这里对Func<RequestDelegate, RequestDelegate>集合进行反转,
            // 逐一执行添加中间件的委托,最后返回第一个中间件委托
            // 这里的作用就是把list里独立的中间件委托给串起来,然后返回反转后的最后一个中间件(实际上的第一个)
            
            // 管道才真正的建立起来,每一个中间件都首尾相连
            foreach (var component in _components.Reverse())
            {
                app = component(app);
            }

            return app;
        }
    }
    public class HttpContext
    {
    }

运行结果:
在这里插入图片描述
在这里插入图片描述

2.5、应用配置

读取配置文件内容:

  1. 通用读取方法在这里插入图片描述
    在这里插入图片描述
  2. 绑定配置模型对象方法
    (1)创建模型类
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    (2)通过IConfiguration对象将配置选项绑定到对象。在这里插入图片描述
    (3)通过注册配置选项服务的方式,获取配置选项的值。
    在这里插入图片描述
    3.读取自定义配置文件的值
    var config=new ConfigurationBuilder().AddJsonFile("jsonconfig.json").Builde();
    这里的config对象就同IConfiguration对象的用法一致。

2.6、环境配置

  1. 方法多环境
    当修改了项目配置文件的环境选项后
    在这里插入图片描述
    Startup类会执行与环境变量对应名称的方法,而不会执行默认的方法。在这里插入图片描述
  2. 类多环境
    首先同样按照方法多环境的步骤,先修改配置文件的环境变量,再修改program类的代码。
    以下代码就是获取调用此方法所在的程序集的名称,然后UseStartup方法就会按照约定去查找对应环境变量的启动类。
    在这里插入图片描述
    由于修改了配置文件,程序会运行StartupDemo类,当没有StartupDemo类时,才会执行默认的Startup类。在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值