• .NET6之MiniAPI(二):request


      为了方便说明这个系列的文章,我引入了一个业务场景,就是一个简单的考试系统(仅作文章Demo案例),ER图见下图。1、系统有题库,试题有答案,分试题类型和试题类别;2、系统有考生用户,可以从题库组织试卷,分配给考生,考生可以考试记录考试结果。

     

     

     

    app.MapGet("/", () => "Hello .NET Mini API!");

      Mini API一大好处是简单明了,拿来就用,比如上面的这行代码,MapGet的参数有两个,第一个是路由信息,第二个实现方法,总体意思就是“这个通道做什么”(这个通道是第一个参数,做什么第二个参数),在这里,第二个参数其实是Lambda表达式,也可以换成一个方法(函数),这个方法是是静态方法也好,实例方法也罢,主要是能完成干什么就可以。

      接下来再细化一些,看一下这两个参数:

    第一个参数:

    app.MapGet("/question/{id:int}", (int id) => $"查询ID为{id}试题");

      这时请求url为:/question/1,并且这里作了限制,必须为整型,如果是字符或小数,这里就报404了。如url换成/question/-1,也是可以通过的,如下:

     

     

       但数据库里肯定是没有-1这样的ID(数据是从1开始增量为1的值),所以这块还要加强路由的规则:

    app.MapGet("/question/{id:min(1)}", (int id) => $"查询ID为{id}试题");

      这样不但卡住负数,也把0排序在外了。如果换成uint会怎么样?

    app.MapGet("/question/{id:uint}", (uint id) => $"查询ID为{id}试题");

     

     

       报的错是从注入容器中找不到uint,这是因为官方的路由参数约束里并没有对uint处理,那如果我们想用无符号整型作参数该怎么办呢?那就自定义路由约束吧。

    var builder = WebApplication.CreateBuilder();
    builder.Services.AddRouting(options =>
    {
        options.ConstraintMap["Uint"] = typeof(MyRouteConstraint.Uint);
    });
    
    var app = builder.Build();
    //参数路由
    app.MapGet("/question/{id:Uint}", (uint id) => $"查询ID为{id}试题");
    app.Run();
    
    namespace MyRouteConstraint
    {
        public class Uint : IRouteConstraint
        {
            public bool Match(HttpContext? httpContext, IRouter? route, string routeKey,RouteValueDictionary values, RouteDirection routeDirection)
            {
                if (values == null || values.Count == 0 || string.IsNullOrWhiteSpace(routeKey))
                {
                    return false;
                }
                var result = uint.TryParse(values[routeKey].ToString(), out uint value);
                if (result)
                {
                    return true;
                }
                return false;
            }
        }
    }

      关于路由的约束还支持正则,具体见如下代码:

    app.MapGet("/area/{postcode:regex(^[0-9]{{3}}-[0-9]{{4}}$)}", (string postcode) => $"邮编:{postcode}");

     

    第二个参数:

    1、从query参数中获取数据:

    app.MapGet("/answer", ([FromQuery(Name="id")]int answerId) => $"[FromQUery]-请求的AnswerID为{answerId}");

     

     

     2、从header获取数据

    app.MapGet("/answers", ([FromHeader(Name = "key")] string secretkey ) => $"[FromHeader]-secretkey为{secretkey}");

     

     

     3、从路由中获取数据

    app.MapGet("/question/{questiontype}", ([FromRoute]string questionType) => $"[FromRoute]-questiontype={questionType}");

     

     

     4、从body中获取数据

    app.MapPost("/answer", ([FromBody] Answer answer) => $"[FromBody]-answer:{System.Text.Json.JsonSerializer.Serialize(answer)}");

     

     

     5、从form表单中获取数据(错误,.net6不支持,因为这是api)

     

     

     6、从Service容器中获取数据,以后说

      上面From都是显式的从Request不同区域取数据,这里要提问个问题,你可以把From特性移除,看各个接口访问是否正常,为什么?


    自定义参数绑定

      我们说第二个参数是个方法,如果这个方法的参数比较复杂,那该怎么处理?官方提供了两个自定义绑定参数的方式。看下面的demo,比如我要查询某个区域的所有酒店,传入的参数是一个坐标组,然后就可以在后台查询出这个范围内的酒店,因为要接收一个复杂类型,但用Request.Query接收到的是字符串,所以这两个自定义绑定就负责完成转换工作(注:当然可以不用这个方式,Post一个Json的Body也是可以的)

    using System.Reflection;
    
    var app= WebApplication.Create();
    //自定义参数绑定 area=[(35.721875, 139.786564),(35.723903, 139.803464),(35.705806, 139.806078),(35.705118, 139.779927)]
    app.MapGet("/area1/hotel", (Area1 area) => $"TryParse Area1:{System.Text.Json.JsonSerializer.Serialize(area)}");
    app.MapGet("/area2/hotel", (Area2 area) => $"BindAsync Area2:{System.Text.Json.JsonSerializer.Serialize(area)}");
    
    app.Run();
    
    public class Area1
    {
        public Coordinates[]? Coordinateses { get; set; }
        public static bool TryParse(string? value, IFormatProvider? provider, out Area1? area)
        {
            var CoordinatesGroupStrings = value?.Split(new string[] { "[(", ")]", "),(" },
                    StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (CoordinatesGroupStrings != null)
            {
                var coordinatesList = new List<Coordinates>();
                foreach (var coordinateGroupString in CoordinatesGroupStrings)
                {
                    var coordinateStrings = coordinateGroupString.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
    
                    var latitudeResult = double.TryParse(coordinateStrings[0], out double latitude);
                    var longitudeResult = double.TryParse(coordinateStrings[1], out double longitude);
                    if (latitudeResult && longitudeResult)
                    {
                        coordinatesList.Add(new Coordinates(latitude, longitude));
                    }
                }
                area = new Area1 { Coordinateses = coordinatesList.ToArray() };
                return true;
            }
            area = null;
            return false;
        }
    }
    public record Coordinates(double Latitude, double Longitude);
    
    public class Area2
    {
        public Coordinates[]? Coordinateses { get; set; }
        public static ValueTask<Area2?> BindAsync(HttpContext context, ParameterInfo parameter)
        {
            var CoordinatesGroupStrings = context.Request.Query["area"].ToString().Split(new string[] { "[(", ")]", "),(" },
                   StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (CoordinatesGroupStrings != null)
            {
                var coordinatesList = new List<Coordinates>();
                foreach (var coordinateGroupString in CoordinatesGroupStrings)
                {
                    var coordinateStrings = coordinateGroupString.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
    
                    var latitudeResult = double.TryParse(coordinateStrings[0], out double latitude);
                    var longitudeResult = double.TryParse(coordinateStrings[1], out double longitude);
                    if (latitudeResult && longitudeResult)
                    {
                        coordinatesList.Add(new Coordinates(latitude, longitude));
                    }
                }
                return ValueTask.FromResult<Area2?>(new Area2 { Coordinateses = coordinatesList.ToArray() });
            }
            return ValueTask.FromResult<Area2?>(null);
        }
    }
      
      想要更快更方便的了解相关知识,可以关注微信公众号 
     
  • 相关阅读:
    phpQuery—基于jQuery的PHP实现
    php 知乎爬虫
    windows下安装php5.5的redis扩展
    Redis 安装
    使用AngularJS创建应用的5个框架
    Redis能干啥?细看11种Web应用场景
    前端开发必须知道的JS之闭包及应用
    javascript深入理解js闭包
    day16<集合框架+>
    day15<集合框架>
  • 原文地址:https://www.cnblogs.com/axzxs2001/p/16259729.html
Copyright © 2020-2023  润新知