.NET5梳理

一、前言

为什么要搭建.Net Core/.NET5/.NET6/.NETX等平台,跨平台!!!而且比.Net 更容易搭建,速度也更快,所有的包均有Nuget提供,不再像以前的单纯引入组件。

1、.net core 框架性能测试

http://www.techempower.com/benchmarks/ 我们可以通过这个web框架性能测试来看看 aspcore 的性能

2、.net core 执行过程 

3、中间件执行过程

启动的时候先执行该中间件类的构造函数,然后一路 Next() ;下去,返回的时候,正好是反向的,执行的是该类的逻辑部分:

4、AOP切面

二、创建Core项目

1、创建过程

具体的创建过程直接看官网文档即可Get started with ASP.NET Core

2、注意事项

开启.net开发前,需要先下载相应的SDK和Runtime。可以根据需要官网下载

  • SDK 和 RunTime 的区别:SDK 是用来开发 NetCore 的,内部捆绑了 Runtime 运行时;但是如果只想运行 NetCore 项目的话,只需要在服务器中安装 Runtime 运行时即可。
  • 判断安装成功:cmd中直接运行dotnet,如果有结果说明安装成功。

  • Https问题:如下图,启用了https安全访问协议,如果启用的话,每次接口都需要是https:xxx,如果是测试可以不用勾选。有很多小伙伴勾选了这个,但是还是一直使用 http 协议去访问,导致找不到响应的接口地址。如果你的项目已经创建好了,每次访问都是HTTPS的,但是你不想这么做,可以在 launthSettings.json 文件中,把sslPort 端口号改成0即可。

三、项目整体结构分析

1、Program.cs

using HYEfficiency.Extensions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace HYEfficiencyCore
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseSeriLog()
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

这个Program是程序的入口,Main方法里面的内容主要是用来配置和运行程序的。因为我们的web程序需要一个宿主,所以 BuildWebHost这个方法就创建了一个WebHostBuilder。而且我们还需要Web Server,asp.net core 自带了两种http servers,一个是WebListener, 它只能用于windows系统; 另一个是kestrel, 它是跨平台的。kestrel是默认的web server,就是通过UseKestrel()这个方法来启用的。但是我们开发的时候使用的是IIS Express,调用UseIISIntegration()这个方法是启用IIS Express, 它作为Kestrel的Reverse Proxy server来用。

如果在windows服务器上部署的话, 就应该使用IIS作为Kestrel的反向代理服务器来管理和代理请求。如果在linux上的话, 可以使用apache, nginx等等的作为kestrel的proxy server。当然也可以单独使用kestrel作为web 服务器,但是使用iis作为reverse proxy还是有很多有优点的: 例如IIS可以过滤请求,管理证书,程序崩溃时自动重启等。

UseStartup<Startup>(), 这句话表示在程序启动的时候, 我们会调用Startup这个类,Build()完之后返回一个实现了IWebHost接口的实例(WebHostBuilder),然后调用Run()就会运行Web程序,并且阻止这个调用的线程,直到程序关闭。

关于Program.cs具体可以参考.NET Core项目解读 启动原理(program.cs和startup.cs)

2、Startup.cs

using HYEfficiency.Extensions;
using HYEfficiency.Helpers;
using HYEfficiency.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.IdentityModel.Tokens.Jwt;

namespace HYEfficiencyCore
{
    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.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

ConfigureServices方法是用来把services注册到容器中去,并配置这些services。这个容器是用来进行dependency injection的,所有注入的services在以后写代码的时候,都可以将它们注入(inject)进去。例如上面的Configure方法的参数, app, env, loggerFactory都是注入进去的services。

Configure方法是asp.net core程序用来具体指定如何处理每个http请求的,例如我们可以让这个程序知道我使用mvc来处理http请求,那就调用app.UseMvc()这个方法就行. 但是目前, 所有的http请求都会导致返回"Hello World!"。

看一看我们项目的最后,Configure方法是如何配置的:

复制代码
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                // 在开发环境中,使用异常页面,这样可以暴露错误堆栈信息,所以不要放在生产环境。
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // 在非开发环境中,使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。
                // 强制实施 HTTPS 在 ASP.NET Core,配合 app.UseHttpsRedirection
                //app.UseHsts();

            }

            #region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //之前是写死的
                //c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
                //c.RoutePrefix = "";//路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉

                //根据版本名称倒序 遍历展示
                typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
                {
// 注意这个 ApiName 和 要和上边 ConfigureServices 中配置swagger的name要大小写一致,具体查看我的blog.core源码 c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}"); }); }); #endregion #region Authen //app.UseMiddleware<JwtTokenAuth>();//注意此授权方法已经放弃,请使用下边的官方验证方法。但是如果你还想传User的全局变量,还是可以继续使用中间件 app.UseAuthentication(); #endregion #region CORS //跨域第二种方法,使用策略,详细策略信息在ConfigureService中 app.UseCors("LimitRequests");//将 CORS 中间件添加到 web 应用程序管线中, 以允许跨域请求。 //跨域第一种版本,请要ConfigureService中配置服务 services.AddCors(); // app.UseCors(options => options.WithOrigins("http://localhost:8021").AllowAnyHeader() //.AllowAnyMethod()); #endregion // 跳转https app.UseHttpsRedirection(); // 使用静态文件 app.UseStaticFiles(); // 使用cookie app.UseCookiePolicy(); // 返回错误码 app.UseStatusCodePages();//把错误码返回前台,比如是404 app.UseMvc(); }
复制代码

3、appsettings.json

4、wwwroot

5、launchSettings.json

四、核心知识点 

1、Routing路由

路由有两种方式:Convention-based (按约定),attribute-based(基于路由属性配置的)。其中convention-based (基于约定的) 主要用于MVC (返回View或者Razor Page那种的)。Web api 推荐使用attribute-based。这种基于属性配置的路由可以配置Controller或者Action级别, uri会根据Http method然后被匹配到一个controller里具体的action上。

常用的Http Method有:

  • Get,查询 HttpGet  '/api/product', '/api/product/1'
  • POST,创建 HttpPost, '/api/product'
  • PUT 整体修改更新 HttpPut, '/api/product/1'
  • PATCH 部分更新 HttpPatch, '/api/product/1'
  • DELETE 删除,HttpDelete, '/api/product/1

还有一个Route属性(attribute)也可以用于Controller层,它可以控制action级的URI前缀。

复制代码
namespace Api.Controllers
{
    //[Route("api/product")]
    [Route("api/[controller]")]
    public class ProductController: Controller
    {
        [HttpGet]
        public JsonResult GetProducts()
        {
            return new JsonResult(new List<Product>
            {
                new Product
                {
                    Id = 1,
                    Name = "牛奶",
                    Price = 2.5f
                },
                new Product
                {
                    Id = 2,
                    Name = "面包",
                    Price = 4.5f
                }
            });
        }
    }
}
 
复制代码

使用[Route("api/[controller]")],它使得整个Controller下面所有action的uri前缀变成了"/api/product", 其中[controller]表示XxxController.cs中的Xxx(其实是小写)。也可以具体指定, [Route("api/product")],这样做的好处是,如果ProductController重构以后改名了,只要不改Route里面的内容,那么请求的地址不会发生变化。然后在GetProducts方法上面,写上HttpGet,也可以写HttpGet(),它里面还可以加参数,例如: HttpGet("all"), 那么这个Action的请求的地址就变成了 "/api/product/All"。

2、内容协商 Content Negotiation

如果 web api提供了多种内容格式,那么可以通过Accept Header来选择最好的内容返回格式: 例如:application/json, application/xml等等。如果设定的格式在web api里面没有,那么web api就会使用默认的格式。asp.net core 默认提供的是json格式,也可以配置xml等格式。目前只考虑 Output formatter,就是返回的内容格式。如果想输出xml格式,就配置这里: 

3、Validation 验证

针对上面的Post方法,  如果请求没有Body,参数product就会是null,这个我们已经判断了;如果body里面的数据所包含的属性在product中不存在,那么这个属性就会被忽略。但是如果body数据的属性有问题,比如说name没有填写, 或者name太长,那么在执行action方法的时候就会报错,这时候框架会自动抛出500异常,表示是服务器的错误,这是不对的。这种错误是由客户端引起的,所以需要返回400 Bad Request错误。验证Model/实体,asp.net core 内置可以使用 Data Annotations进行。 

复制代码
 
using System;
using System.ComponentModel.DataAnnotations;

namespace CoreBackend.Api.Dtos
{
    public class ProductCreation
    {
        [Display(Name = "产品名称")]
        [Required(ErrorMessage = "{0}是必填项")]
        // [MinLength(2, ErrorMessage = "{0}的最小长度是{1}")]
        // [MaxLength(10, ErrorMessage = "{0}的长度不可以超过{1}")]
     [StringLength(10, MinimumLength = 2, ErrorMessage = "{0}的长度应该不小于{2}, 不大于{1}")] public string Name { get; set; } [Display(Name = "价格")] [Range(0, Double.MaxValue, ErrorMessage = "{0}的值必须大于{1}")] public float Price { get; set; } } }
 
复制代码

这些Data Annotation (理解为用于验证的注解),可以在System.ComponentModel.DataAnnotation找到,例如[Required]表示必填, [MinLength]表示最小长度, [StringLength]可以同时验证最小和最大长度,[Range]表示数值的范围等等很多。[Display(Name="xxx")]的用处是给属性起一个比较友好的名字。其他的验证注解都有一个属性叫做 ErrorMessage (string), 表示如果验证失败,就会把ErrorMessage的内容添加到错误结果里面去。这个ErrorMessage可以使用参数,{0}表示Display的Name属性,{1}表示当前注解的第一个变量,{2}表示当前注解的第二个变量。在Controller里面添加验证逻辑:

复制代码
      
[HttpPost]
        public IActionResult Post([FromBody] ProductCreation product)
        {
            if (product == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var maxId = ProductService.Max(x => x.Id);
            var newProduct = new Product
            {
                Id = ++maxId,
                Name = product.Name,
                Price = product.Price
            };
            ProductService.Add(newProduct);

            return CreatedAtRoute("GetProduct", new { id = newProduct.Id }, newProduct);
        }
 
复制代码

 

原文地址:https://www.cnblogs.com/qtiger/p/15305800.html