Loading

Asp.net core 少走弯路系列教程(七)WebApi 学习

前言

新人学习成本很高,网络上太多的名词和框架,全部学习会浪费大量的时间和精力。

新手缺乏学习内容的辨别能力,本系列文章为新手过滤掉不适合的学习内容(比如多线程等等),让新手少走弯路直通罗马。

作者认为新人应该先打好基础,不要直接学习框架,例如先掌握 SQL 再使用 EFCore 框架。

作者只传授数年内不会变化的知识,让新手学习快速进入跑道受益终身。

分享使我快乐,请务必转发给同学,朋友,让大家都少走一些弯路!!


到此你已经初步掌握了 HTTP 协议,C# 语言基础知识,这一篇将带你进入 WebApi 服务器应用开发的环境。

对于 Web 服务端程序来讲,一般分两种请求内容,静态和动态:

  • 静态的内容比如 .html/.css/.jpg,他们一般会存放在固定的 web 目录之内
  • 动态的内容比如查询投票数量、发表博客文章

Asp.net core 框架入门

Asp.net core 框架,它是官方为数不多的优秀框架,其实蛮复杂不建议新手进行系统的全面学习,如果有条件甚至推荐先学习 expressjs 框架(nodejs)再来看 Asp.net core 会简单很多。

创建一个 WebApi 程序很简单,在控制台使用命令:

dotnet new webapi


然后你就可以 F5 运行项目了,快点打开 ide 试试吧!

  • AddControllers/MapControllers 应用 Controllers 目录下的控制台类
  • AddSwaggerGen/UseSwagger/UseSwaggerUI 应用 Swagger 接口管理器,你可以把它发给前端开发者,提供了哪些 HTTP 接口一目了然


Controller 控制器

  • WeatherForecastController 继承 ControllerBase
  • [Route("[controller]")] 注解指定 HTTP 请求的路径是 WeatherForecast
  • Get 方法 [HttpGet("GetWeatherForecast")] 指定 HTTP 请求的方法为 GET,最终请求的路径是 WeatherForecast/GetWeatherForecast
  • Get 方法返回值最终被序列化成 Json 格式返回给浏览器


思考:如果使用 [HttpPost] 是不是指定方法为 POST?

[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet("GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

之前讲 HTTP 协议时,有讲到 QueryString、Form、JSON 三种请求报文的参数格式,服务器获取参数的办法:

    [HttpGet("QueryString")]
    public string QueryStringTest([FromQuery] int id, [FromQuery] string wd)
    {
        return id.ToString() + ", " + wd;
    }

    [HttpPost("Form")]
    public string FormTest([FromForm] int id, [FromForm] string wd)
    {
        return id.ToString() + ", " + wd;
    }

    [HttpPost("JSON")]
    public string JsonTest([FromBody] JsonTestInputModel json)
    {
        return json.id.ToString() + ", " + json.wd;
    }
    class JsonTestInputModel
    {
        public int id { get; set; }
        public string wd { get; set; }
    }

关于异步,建议先把同步熟练之后再学习不迟,混起来学机制不明白还容易乱用。


什么是依赖注入(Denpendency Injection)

到底依赖注入是什么? 为什么要用它? 初学者特别容易对控制反转IOC(Iversion of Control),DI等概念搞晕。

1、首先我们得知道什么是依赖

当一个类需要另一个类协作来完成工作的时候就产生了依赖。比如我们在AccountController这个控制器需要完成和用户相关的注册、登录 等事情。其中的登录我们由EF结合Idnetity来完成,所以我们封装了一个EFLoginService。这里AccountController就有一个ILoginService的依赖。

2、什么是注入

注入体现的是一个IOC(控制反转的的思想)。在反转之前 ,我们先看看正转。

private ILoginService<ApplicationUser> _loginService;
public AccountController()
{
  _loginService = new EFLoginService()
}

大师说,这样不好。你不应该自己创建它,而是应该由你的调用者给你。于是你通过构造函数让外界把这两个依赖传给你。

private ILoginService<ApplicationUser> _loginService;
public AccountController(ILoginService<ApplicationUser> loginService)
{
  _loginService = loginService;
}

把依赖的创建丢给其它人,自己只负责使用,其它人丢给你依赖的这个过程理解为注入。

3、为什么要反转?

为了在业务变化的时候尽少改动代码可能造成的问题。比如我们现在要把从EF中去验证登录改为从Redis去读,于是我们加了一个 RedisLoginService。这个时候我们只需要在原来注入的地方改一下就可以了。

因为EFLoginService和RedisLoginService都实现了接口ILoginService,所以我们直接在调用方传入RedisLoginService即可。(即将EFLoginService替换为RedisLoginService)

4、什么是容器?

上面我们在使用AccountController的时候,我们自己通过代码创建了一个ILoggingServce的实例。想象一下,一个系统中如果有100个这样的地方,我们是不是要在100个地方做这样的事情? 控制是反转了,依赖的创建也移交到了外部。现在的问题是依赖太多,我们需要一个地方统一管理系统中所有的依赖,所以容器诞生了。

容器负责两件事情:

  • 绑定服务与实例之间的关系
  • 获取实例,并对实例进行管理(创建与销毁)


Asp.net core DI

在.NET Core 中 DI 的核心分为两个组件:IServiceCollection和 IServiceProvider。

  • IServiceCollection 负责注册
  • IServiceProvider 负责提供实例
builder.Services
  //.AddTransient<ILoginService, EFLoginService>() //每一次GetService都会创建一个新的实例
  .AddScoped<ILoginService, EFLoginService>() //在同一个Scope内只初始化一个实例
  //.AddSingleton<ILoginService, EFLoginService>(); //整个应用程序生命周期以内只创建一个实例 

提示:每个 HTTP 请求都会创建一个 Scope 生命范围,所以 AddScoped 是最常用的方法。

public class WeatherForecastController : ControllerBase
{
    private readonly ILoginService  _loginService;

    public WeatherForecastController(ILoginService loginService)
    {
        _loginService = loginService;
    }
}

中间件管道

app.Use(async (context, next) =>
{
    Console.WriteLine("middleware1 : in");
    await next.Invoke();
    Console.WriteLine("middleware1 : out");
});
app.Use(async (context, next) =>
{
    Console.WriteLine("middleware2 : in");
    await next.Invoke();
    Console.WriteLine("middleware2 : out");
});
app.Run(async context =>
{
    Console.WriteLine("Hello World");
    await context.Response.WriteAsync("Hello World");
});


Asp.net core 框架还有很多知识,但是对新手而已学到这里算入门了,千万不要指望一下能吃下所有内容(贪吃蛇的后果),只有反复的实战才能彻底领会贯通。

到这里,你已经对 Asp.net core 框架有了初步的认识,为我们以后深入打下了基础,下一篇我们学习 数据库 CRUD 增删改查 知识吧!


系列文章导航

原创保护,转载请注明出处:https://www.cnblogs.com/FreeSql/p/16782488.html

posted @ 2022-10-11 20:29  FreeSql  阅读(3034)  评论(1编辑  收藏  举报