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-dataapplication/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。

相关推荐
why1512 小时前
腾讯(QQ浏览器)后端开发
开发语言·后端·golang
浪裡遊2 小时前
跨域问题(Cross-Origin Problem)
linux·前端·vue.js·后端·https·sprint
声声codeGrandMaster2 小时前
django之优化分页功能(利用参数共存及封装来实现)
数据库·后端·python·django
呼Lu噜3 小时前
WPF-遵循MVVM框架创建图表的显示【保姆级】
前端·后端·wpf
bing_1583 小时前
为什么选择 Spring Boot? 它是如何简化单个微服务的创建、配置和部署的?
spring boot·后端·微服务
学c真好玩3 小时前
Django创建的应用目录详细解释以及如何操作数据库自动创建表
后端·python·django
Asthenia04123 小时前
GenericObjectPool——重用你的对象
后端
Piper蛋窝3 小时前
Go 1.18 相比 Go 1.17 有哪些值得注意的改动?
后端
excel3 小时前
招幕技术人员
前端·javascript·后端
盖世英雄酱581364 小时前
什么是MCP
后端·程序员