一、准备工作

  1. 打开Visual Studio,新建项目,选择ASP.NET Core Web API并创建Demo工程。
  2. 查看解决方案资源管理器,可以看到以下结构:
    Controllers 文件夹:存放控制器(Controller),每个控制器里可以写多个API方法。
    Program.cs:程序入口,配置服务和管道。
    appsettings.json:配置文件(比如端口、日志等)。

二、编写服务端代码

  1. Controller文件夹下新建一个MVC控制器,取名为MathController.cs,然后开始编写相应代码:
using Microsoft.AspNetCore.Mvc;

namespace WebApiTest.Controllers;
[ApiController]//声明这是一个控制器,有以下作用:
               //自动验证模型(如果参数不符合要求,自动返回错误信息),
               //自动绑定请求数据(比如从URL、Body中取参数)
               //默认返回JSON格式(无需额外配置)
[Route("api/math")]//路由模板,定义了这个控制器所有方法的基础URL前缀。
public class MathController : Controller
{
    [HttpGet("add")]//表示这个方法响应HTTP的GET请求。"add"是附加在基础路由后的路径片段,完整的URL是api/math/add
    public IActionResult Add(int a, int b)//这里两个整数参数,默认会从URL的查询字符串(QueryString)中获取,比如?a=1&b=2。
    {
        int result = a + b;
        return Ok(new { a, b, result });//这里的Ok()是ControllerBase提供的方法,它返回一个HTTP 200 OK状态码,并自动将传入的匿名对象序列化为JSON格式。
    }

    [HttpPost("greet")]//表示这个方法响应HTTP POST请求,完整的URL是api/math/greet。
    public IActionResult Greet([FromBody] string name)//[FromBody]声明参数绑定特性,告诉ASP.NET Core:这个name参数的值要从请求体Body中读取,并且请求体应该是JSON格式。
    {
        string message = $"Hello, {name}!";
        return Ok(new { message });//将一个包含message属性的匿名对象序列化为JSON发送给客户端
    }
}

三、代码关键点

IActionResult是一个接口,表示一个操作的结果。它允许返回各种类型的HTTP响应:成功(Ok)、失败(BadRequest)、未找到(NotFound)、重定向等。

Ok()ControllerBase提供的一个便捷方法,它返回一个OkObjectResult对象,这个对象实现了IActionResult接口,并负责将传入的对象序列化为JSON,并设置状态码为 200。

四、常见问题

Q: 为什么方法名是Add或Greet,但URL里用的是小写的add和greet?
A: 路由模板里 [HttpGet(“add”)] 明确指定了路径为add,所以方法名不重要。这是一种约定,也可以写成[HttpGet]然后方法名就是路径,但显式指定更灵活。

Q: 如果想让GET方法接收复杂对象怎么办?
A: GET通常只用简单参数(因为放在URL里),复杂对象一般用POST放在请求体中。如果确实需要,可以用 [FromQuery] 来绑定对象属性。

Q: 如何返回错误信息?
A: 可以用return BadRequest(“错误信息”); 返回400状态码;或者return NotFound(); 返回404等。

Q: [ApiController]必须写吗?
A: 不是必须,但强烈推荐。它提供了很多便利,比如自动处理400错误、自动绑定复杂类型等。如果没有这个特性,可能需要手动处理一些事情。

五、编写客户端代码

using System.Text;
using System.Text.Json;
using static System.Net.Mime.MediaTypeNames;
using System.Text.Unicode;

//服务端地址,这里需要改成运行服务端时看到的实际地址和端口
string baseUrl = "https://localhost:XXXX/api/math";

//1. 调用GET方法(加法)
using (HttpClient client = new HttpClient())//HttpClient是发送HTTP请求的核心类。using确保使用完后自动释放资源,避免资源泄漏
{

    string url = $"{baseUrl}/add?a=1&b=2";    //调用GET: /add?a=1&b=2
    HttpResponseMessage response = await client.GetAsync(url);//GetAsync发起一个异步GET请求。返回的response对象包含服务器响应的所有信息:状态码、头部、内容等

    if (response.IsSuccessStatusCode)//判断是否为成功状态码
    {
        string json = await response.Content.ReadAsStringAsync();//响应内容(JSON字符串)以字节流形式存储,通过ReadAsStringAsync转为字符串

        var result = JsonSerializer.Deserialize<Dictionary<string, int>>(json);//解析JSON(匿名类型)
        Console.WriteLine($"Add方法结果: {result["a"]} + {result["b"]} = {result["result"]}");//通过字典的键访问值
    }
    else
    {
        Console.WriteLine($"调用Add方法失败: {response.StatusCode}");
    }
}

//2. 调用POST方法(Greet方法)
using (HttpClient client = new HttpClient())
{

    string name = "World";    //准备JSON请求体
    string jsonBody = $"\"{name}\""; //序列化成JSON字符串
    var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");//StringContent用来封装请求体内容。参数依次是:内容字符串、编码(UTF8)、媒体类型(application/json),告诉服务器我们发送的是JSON数据

    string url = $"{baseUrl}/greet";//调用/greet路径
    HttpResponseMessage response = await client.PostAsync(url, content);//PostAsync发送POST请求,第二个参数是请求体内容

    if (response.IsSuccessStatusCode)
    {
        string json = await response.Content.ReadAsStringAsync();
        var result = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
        Console.WriteLine($"greet方法结果: {result["message"]}");
    }
    else
    {
        Console.WriteLine($"调用greet失败: {response.StatusCode}");
    }
}

六、代码关键点

HttpClient:.NET 中发送 HTTP请求的主要类,支持 GET、POST 等方法。
HttpResponseMessage:代表HTTP响应,包含状态码、内容等。
StringContent:用于包装请求体的内容,可指定编码和媒体类型。
JsonSerializer:.NET自带的JSON序列化/反序列化类(需要System.Text.Json命名空间)。
Dictionary<TKey, TValue>:键值对集合,常用于解析动态JSON对象。
using语句:确保对象在离开作用域时被正确释放。

七、常见问题

Q: 为什么jsonBody要写成"\"World\""
A: 因为HTTP请求体要求是纯文本,而JSON规定字符串必须用双引号包围。如果直接发送World,服务器可能无法解析。

Q: 为什么这里用Dictionary而不是自定义类?
A: 为了简化演示,如果JSON结构固定,也可以定义一个类来反序列化。

Q: 如果网络不通或服务未启动会怎样?
A: GetAsyncPostAsync会抛出异常,代码中未捕获,程序会崩溃。实际开发应加入try-catch

Q: 多次使用HttpClient的建议
A: 实际项目中推荐复用同一个HttpClient实例(单例模式),避免频繁创建带来的性能问题。但这里为了简单,每个请求独立创建也是可行的。

八、流程说明

  1. 客户端向https://localhost:XXXX/api/math/add?a=1&b=2发送一个GET请求。

  2. ASP.NET Core的路由系统匹配到MathController的Add方法,因为URL符合api/math/add并且是GET方法。

  3. 模型绑定器自动从查询字符串中取出a=1和b=2,转换成整数,传给Add方法。

  4. 方法内部计算result = 1+2 = 3,然后返回Ok结果。

  5. ASP.NET Core把返回的匿名对象序列化成JSON,并打包成HTTP 200响应发送回去。

  6. 客户端收到JSON,解析并使用。

对于POST请求类似,只是数据放在请求体中,并且方法签名中用了 [FromBody] 告诉框架从Body中取。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐