.NET 6入门笔记

.NET 6入门

1、ApiControllerAttribute

  • 实际上[ApiController]ApiControllerAttribute类, 要在方括号外面写全, 方括号内不用写全

2、ApiController数据源推断

(0)参数特性(过时)

  • .net core 3.1以前, 如果方法内传递的参数未知, 需要使用如下特性修饰参数, 否则报错

  • .net core 3.1以后, 如果控制器上没有[ApiController]使用如下修饰

  • 自从有了[ApiController], 可以自动自动推断对象

特性 绑定源
[FromBody] 该参数来自请求正文
[FromForm] 请求正文中的表单数据
[FromHeader] 请求标头
[FromQuery] 请求查询字符串参数
[FromRoute] 当前请求中的路由参数
[FromServices] 作为操作参数插入的服务请求
namespace SecondDemo.Controllers
{
    //[ApiController]
    [Route("/api/[controller]/[action]")]
    public class TestPostController : ControllerBase
    {
        //使用Model对象接受前端请求的数据
        [HttpPost]
        public string Post([FromBody] TestPostViewModel? model)
        {
            return model.I + model.Name;
        }
    }
}
  • [ApiController]属性可以用于控制器类, 以启用下述API特定固定行为

    • 属性路由要求

    • 自动HTTP400响应

    • 绑定源参数推断

    • Multipart / form-data请求推理, 多文件、数据上传, 自动请求推理

    • 错误状态代码的问题详细信息

    • 数据验证, 不符合规则将报错

      namespace SecondDemo.Models
      {
          public class TestPostViewModel
          {
              [MaxLength(3)] //最大长度为3
              [Required] //必填项
              public int I { get; set; }
              public string? Name { get; set; }
          }
      }

       

(1)使用Model接受前端传来的json对象

<script>
    const { createApp, ref } = Vue;
    const app = createApp({
        setup() {
            const userName = ref("NiHao");
            const onGetValue = () => {
                axios.post("http://localhost:5203/api/HelloWorld/Post", {i:666, name:"asd"})
                    .then(res =>{
                        userName.value = res.data;
                    })
            }
            return {userName, onGetValue}
        }
    })
</script>
namespace SecondDemo.Models
{
    public class TestPostViewModel
    {
        public int I { get; set; }
        public string? Name { get; set; }
    }
}
namespace SecondDemo.Controllers
{
    [ApiController]
    [Route("/api/[controller]/[action]")]
    public class TestPostController : ControllerBase
    {
        //使用Model对象接受前端请求的数据
        [HttpPost]
        public string Post(TestPostViewModel? model)
        {
            return model.I + model.Name;
        }
    }
}

3、创建Restful风格API

API 描述 请求正文 响应正文
GET /api/todoitems 获取所有待办事项 None 待办事项的数组
GET /api/todoitems/{id} 按ID获取项 None 待办事项
POST /api/todoitems 添加新项 待办事项(实体) 待办事项(实体的ID)
PUT /api/todoitems/{id} 更新现有项 待办事项(实体) None
DELETE /api/todoitems/{id} 删除项 None None

4、一次WebApp完整过程

5、三个返回值类型

ASP.NET Core提供以下WebApi控制器操作返回类型选项

  • 特定类型

  • IActionResult

  • ActionResult

(1)特定类型

  • 最简单的操作返回基元或者复杂数据类型(如sring或自定义对象)

[HttpGet]
public List<Produch> Get()
{
    return _repostiory.GetProducts();
}

(2)IActionResult

  • 做微服务项目, 由于状态码信息少, 占带宽少, 项目并发访问资源占用少, 使用状态码作为返回值, 进行实例心跳监测

  • 当操作中可能有多个ActionResult返回类型时, 时候用IActionResult, 表示多种Http状态码, 此类别中的某些常见返回类型为BadRequestResult(400)、NotFound(404)、OkObjectResult(200)

  • Ok()便利方法, 作为return new OkObjectResult(arg)的简写, 可以传递一个参数, 但是文档里不知道返回值类型示例

namespace SecondDemo.Controllers
{
    [ApiController]
    [Route("/api/[controller]/[action]")]
    public class TestIActionResultController : ControllerBase
    {
        //返回200不带参数
        [HttpGet]
        public IActionResult GetOkNoArgs()
        {
            //Ok()便利方法, 作为return new OkObjectResult(arg)的简写
            return Ok();
        }
        
        //返回200带个参数
        [HttpGet]
        public IActionResult GetOk()
        {
            return Ok(new TestPostViewModel { I = 123, Name = "asd" });
        }
    }
}

(3)ActionResult

  • ASP.NET core包括面向Web Api控制器操作的ActionResult类型

    • 这种返回值既能返回普通类型返回值

    • 又能返回指定状态码

//使用ActionResult
[HttpGet("{id}")]
public ActionResult<Product> GetProductById(int id) 
{
    if (id != 1)
    {
        return NotFound();
    }
    return new Product { Id = 1, Name = "asda"};
}
//同样, 使用IActionResult也能完成任务
[HttpGet("{id}")]
public IActionResult GetProductById(int id)
{
    if (id != 1) 
    { 
        return NotFound(); 
    }
    return Ok(new Product { Id = 1, Name = "dnisai" });
}

6、Minimal APIS

最小的API包括, 在Program.cs中声明

  • 新的承载API

  • WebApplicationWebApplicationBuilder

  • 新的路由API

  • MapXxx(上下文地址, 终结者后执行委托)

    • 可以理解为请求的url

    • 执行完需要返回/响应的东西

    • 委托可以直接声明、或者lambda表达式, 或者静态方法

//注册服务
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
​
//创建webapp
var app = builder.Build();
​
//创建委托
​
//MapXxx(路由地址, 当执行到终结者路由时 需要执行的委托
//                          () => statement...; return...;)
app.MapGet("/MinimalTest", () => "hello get");
app.MapPost("/MinimalTest", (Product p) => { return new TestPostViewModel { I = p.Id, Name = p.Name }; });
//使用静态方法作为委托参数
app.MapPut("/MinimalTest", Hello.HelloPut);
//使用Lambda表达式声明非匿名方法委托
string HelloDelete() => "hello delete";
app.MapDelete("/MinimalTest", HelloDelete);
​
//开启webapp
app.Run();
public class Hello
{
    public static string HelloPut()
    {
        return "hello";
    }
}

(1)路由约束

  • 限制路由的匹配行为

//路由约束, 约束路由参数
//只能传递, int类型的id作为参数
app.MapPost("MiniMalConsTest/{id:int}", (string id) => "符合传参规定 id:" + id);
//使用正则表达式, 只能传递a-z\0-9\下划线
app.MapPost("MiniMalConsTest/{password:regex(^[a-z0-9_-]+$)}", (string password) => "符合传参规定 pwd:" + password);

(2)传参形式

  • 常见的请求的传参形式与Restful保持一致

  • MinimalAPIS有一种依赖注入的传参形式

7、控制反转、依赖注入

(1)IOC

  • 逻辑层、数据库链接层, 在使用的时候, 不再是我们去请求他们, 而是他们主动注入服务

  • 在ASP.NET Core 6中, IOC容器是ServiceCollection服务收集器

    • 是一个存放服务的容器

    • 服务就是在开发中需要的各种类的统称

    • ServiceCollection不仅能在Web项目中使用

(2)DI注入

  • 注入方式

    • 构造函数注入(基础)

    • 属性注入(好用, 使用增强容器)

      • 增强容器AutoFac, 可以进行属性注入, 也可以进行AOP面向切面编程, 但是打开就是全局AOP, 性能不高, 不如用原生AOP

    • 方法注入(基本不用)

  • 依赖注入是实现控制反转的一种手段或方法

  • 谁依赖谁: 应用程序依赖IOC容器

  • 为什么依赖: 应用程序需要IOC容器来提供对象需要的外部资源

  • 谁注入谁: IOC容器注入应用程序某个对象, 应用程序所依赖的对象

  • 注入了什么, 注入某个对象所需要的外部资源(对象、资源、常量数据)

(3)WebApi中使用例子

1.创建Service

namespace SecondDemo.Services
{
    public class UserService
    {
        public string GetUserName()
        {
            return "my username";
        }
    }
}

2.在Program.cs中加装顺态服务注册, 将UserService放入IOC容器

builder.Services.AddTransient<UserService>();

3.在需要的Controller中, 使用属性+构造器注入, 并使用

namespace SecondDemo.Controllers
{
    [ApiController]
    [Route("/api/[controller]/[action]")]
    public class TestIOCController : ControllerBase
    {
        //创建属性
        private UserService UserService { get; }
        //使用构造器注入UserService
        public TestIOCController(UserService userService) 
        {
            this.UserService = userService;
        }
​
        //测试IOC容器DI注入
        [HttpGet]
        public string GetUserName()
        {
            return UserService.GetUserName();
        }
    }
}

(5)在Minimal Apis中使用

//Minimal APIS使用依赖注入
app.MapPost("MiniMalIOCDITest", (UserService userService) => userService.GetUserName())

(6)依赖倒置

  • 假如使用接口规范Service, 需要在注册IService, 和Service

  • 使用如下两个泛型的方法去注册IService, 第一泛型是接口, 第二个泛型是实现类

//加装瞬态服务注册, 将 接口类型、实现类型 IUserService、UserService放入IOC容器
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddTransient<UserService>();
(7)IOC生命周期
  • Transient 瞬态生命周期

    • 每次使用该属性的时候都要new一个实例

  • Singleton 单例生命周期

    • 使用该属性的时候new一个实例, 以后都用这个

  • Scoped 作用域生命周期 线程单例

    • 每次请求都会new一个实例, 在这次请求里都用这个

1.使用场景
  • Scoped 不同线程多次共享一个属性

  • Transient 无需共享同一个属性

  • Singleton 只要注册了这个属性就一直有某个属性, 相当于缓存了这个属性

    • builder.Services.AddSingleton<IService>(new Service(1));
2.注册服务
  • 注册瞬态

builder.Services.AddTransient<服务层接口类, 服务层接口实现类>();
builder.Services.AddTransient(typeof(服务层接口类), typeof(服务层接口实现类));
  • 注册线程

builder.Services.AddScoped<服务层接口类, 服务层接口实现类>();
builder.Services.AddScoped<服务层接口类, 服务层接口实现类>(typeof(IService), typeof(IService));
  • 注册单例

builder.Services.AddSingleton<服务层接口类, 服务层接口实现类>();
builder.Services.AddSingleton(typeof(服务层接口类), typeof(服务层接口实现类));
//特点, 传入一个参数
builder.Services.AddSingleton<服务层接口类>(service);

posted on 2023-08-01 00:48  老菜农  阅读(29)  评论(0编辑  收藏  举报

导航