ASP.NET Core Web API 参数传递方式

文章目录


前言

在ASP.NET Core Web API中,参数传递方式多样且灵活,合理选择传递方式对API设计和性能优化至关重要。

一、参数传递方式

路由参数(Route Parameters)

  1. 用途:标识资源路径中的核心参数(如ID、分类名)。

  2. 绑定特性 :FromRoute

  3. 示例 :

    csharp 复制代码
    [HttpGet("products/{id}")]
    public IActionResult GetProduct([FromRoute] int id) 
    {
        // 通过路径如 /api/products/5 获取id=5
    }

查询字符串参数(Query String Parameters)

  1. 用途:用于过滤、分页、排序等可选操作。

  2. 绑定特性 :FromQuery

  3. 示例 :

    csharp 复制代码
    [HttpGet("products")]
    public IActionResult Search([FromQuery] string keyword, [FromQuery] int page = 1) 
    {
        // 请求示例:/api/products?keyword=apple&page=2
    }

请求体参数(Request Body)

  1. 用途 :传递复杂数据结构(如JSON 对象),常用于POST/PUT请求。

  2. 绑定特性 :FromBody

  3. 示例 :

    csharp 复制代码
    [HttpPost("products")]
    public IActionResult CreateProduct([FromBody] ProductDto product) 
    {
        // 请求体为JSON:{ "Name": "Phone", "Price": 999 }
    }

表单数据(Form Data)

  1. 用途 :处理multipart/form-data 或application/x-www-form-urlencoded 格式(如文件上传)。

  2. 绑定特性 :FromForm

  3. 示例 :

    csharp 复制代码
    [HttpPost("upload")]
    public IActionResult UploadFile([FromForm] IFormFile file, [FromForm] string description) 
    {
        // 通过表单提交文件和描述字段
    }

请求头参数(Header Parameters)

  1. 用途 :传递元数据 (如认证令牌 、客户端信息)。

  2. 绑定特性 :FromHeader

  3. 示例 :

    csharp 复制代码
    [HttpGet("user")]
    public IActionResult GetUser([FromHeader(Name = "Authorization")] string authToken) 
    {
        // 从请求头获取Authorization值
    }

服务注入(Service Injection)

  1. 用途:直接注入依赖的服务(如数据库上下文、日志服务)。

  2. 绑定特性 :FromServices

  3. 示例 :

    csharp 复制代码
    [HttpGet("logs")]
    public IActionResult GetLogs([FromServices] ILogger<MyController> logger) 
    {
        logger.LogInformation("Fetching logs...");
        // ...
    }

二、高级用法与技巧

混合参数来源

  1. 场景 :同时使用路由 、查询字符串 和请求体。

  2. 示例:

    csharp 复制代码
    [HttpPut("products/{id}")]
    public IActionResult UpdateProduct(
        [FromRoute] int id,
        [FromQuery] bool forceUpdate,
        [FromBody] ProductDto product
    ) 
    {
        // 请求示例:PUT /api/products/5?forceUpdate=true
        // Body: { "Name": "New Name" }
    }

模型绑定(自动绑定)

  1. 说明:ASP.NET Core自动根据参数名和类型绑定数据,无需显式标注**From\***。

  2. 示例

    csharp 复制代码
    [HttpGet("products")]
    public IActionResult Get(int page, int pageSize) 
    {
        // 自动从查询字符串绑定:/api/products?page=2&pageSize=20
    }

自定义模型绑定

  1. 场景 :处理特殊格式的输入(如自定义日期格式)。

  2. 实现 :继承IModelBinder接口。

  3. 示例 :

    csharp 复制代码
    public class CustomDateBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext context)
        {
            var value = context.ValueProvider.GetValue("customDate").FirstValue;
            // 解析自定义日期格式...
        }
    }
    
    [HttpGet("events")]
    public IActionResult GetEvents([ModelBinder(typeof(CustomDateBinder))] DateTime date) 
    {
        // 使用自定义日期绑定逻辑
    }

三、验证与安全性

数据注解验证

  1. 用途 :通过DataAnnotations验证参数合法性。

  2. 示例 :

    csharp 复制代码
    public class ProductDto
    {
        [Required]
        [StringLength(100)]
        public string Name { get; set; }
    
        [Range(0, 10000)]
        public decimal Price { get; set; }
    }
    
    [HttpPost("products")]
    public IActionResult CreateProduct([FromBody] ProductDto product) 
    {
        if (!ModelState.IsValid) 
        {
            return BadRequest(ModelState);
        }
        // ...
    }

敏感参数处理

  1. 建议 :避免通过URL 传递敏感信息 (如密码 ),改用请求体或Headers。

  2. 错误示例 :

    csharp 复制代码
    // 不推荐:密码暴露在URL中
    [HttpGet("login")]
    public IActionResult Login([FromQuery] string username, [FromQuery] string password) 
    {
        // ...
    }

文件上传安全

  1. 建议 :限制文件类型和大小。

  2. 示例 :

    csharp 复制代码
    [HttpPost("upload")]
    public async Task<IActionResult> Upload([FromForm] IFormFile file)
    {
        if (file.Length > 5 * 1024 * 1024) 
        {
            return BadRequest("文件大小不能超过5MB");
        }
        // ...
    }

四、最佳实践

遵循RESTful设计:

  1. GET:使用路由和查询参数。
  2. POST/PUT:使用请求体传递复杂数据。

明确参数来源:

  1. 显式使用FromRoute、FromQuery等特性,避免歧义。

性能优化:

  1. 避免在GET请求中使用请求体(不符合HTTP规范)。
  2. 大文件上传使用IFormFile,而非Base64编码。

版本控制:

  1. 通过路由或查询参数实现API版本管理:

    csharp 复制代码
    [Route("api/v1/[controller]")]
    public class ProductsV1Controller : ControllerBase { /*...*/ }

文档化:

  1. 使用Swagger/OpenAPI生成文档,明确参数类型和用途

    csharp 复制代码
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    });
    
    app.UseSwagger();
    app.UseSwaggerUI();

五、常见问题

参数绑定失败如何处理?

  1. 方案 :检查模型绑定错误,返回详细错误信息:

    csharp 复制代码
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

如何接收动态参数(如未知的查询键值对)?

  1. 方案 :使用Dictionary<string, string>或动态类型 :

    csharp 复制代码
    [HttpGet("search")]
    public IActionResult Search([FromQuery] Dictionary<string, string> filters) 
    {
        // 处理动态过滤条件
    }

如何处理数组参数?

  1. 示例 :通过查询字符串传递数组:

    csharp 复制代码
    // 请求:/api/products?categories=books&categories=electronics
    [HttpGet("products")]
    public IActionResult GetProducts([FromQuery] List<string> categories) 
    {
        // categories = ["books", "electronics"]
    }

如果参数和上面不一样需要用到FromRoute: FromRoute(Name= "XXX")

  1. 示例 :

    csharp 复制代码
    [HttpGet("{age}/{address}")]
    public ActionResult<Person> GetPersonByAgeAndAddress(int age, string address)
    //如果参数和上面不一样需要用到FromRoute: [FromRoute(Name= "address")]string addre
    //public ActionResult<Person> GetPersonByAgeAndAddress(int age,[FromRoute(Name= "address")]string addre)
    {
        List<Person> plist = new List<Person> {
            new Person ("张三", 32, "湖北"),
            new Person ("李四", 29, "湖南")
        };
    
        var person = plist.SingleOrDefault(a => a.Age == age&&a.Address== address);
        if (person == null)
        {
            return NotFound("无此人员的数据信息");
        }
        else
        {
            return person;
        }
    }

总结

通过合理选择参数传递方式,结合验证和安全性措施,可以构建高效、安全且易维护的Web API。

相关推荐
猿究院_夏燊4 小时前
Spring Bean 生命周期
java·后端·spring
CCblandy6 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
我是人✓6 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端
念念清晰8 小时前
000-OpenJDK17 源码构建:MacOS环境(M芯片)
java·后端
来福猿8 小时前
SpringCloud Config 源码分析:配置拉取、刷新与多环境管理
后端·spring·spring cloud
IT_陈寒10 小时前
React组件莫名重渲染?你可能忘了这个小细节
前端·人工智能·后端
用户98883218717410 小时前
给 .NET 网络调用设定“预算”:用 CancellationTokenSource.CancelAfter 处理超时取消
后端
清风儿32910 小时前
一块不会说话的电表,把我们折腾了半个月
后端
预知同行11 小时前
深入解析 MoE 混合专家模型:从 Router 到 All-to-All 的架构全景与生产实践
后端·架构
upala11 小时前
【仓颉语言入门 · 第二篇 第 8 课】
后端