WebAPI 学习总结
目录
- 一、什么是 WebAPI(理论)
- 二、HTTP 基础(理论)
- 三、请求方式与状态码(理论)
- 四、RESTful 风格(理论)
- 五、WebAPI 项目搭建(实战)
- 六、定义接口——控制器(实战)
- 七、WebAPI 使用 SqlSugar(实战)
- 八、客户端调用 WebAPI(实战)
- 九、项目代码文件结构
- 十、总结与关键要点
一、什么是 WebAPI(理论)
Web API = Web Application Programming Interface(网络应用程序接口)。
- 基于 HTTP 协议的网络应用程序接口,使用 JSON 或 XML 格式传输数据。
- 是服务器端应用程序,允许客户端通过 HTTP 请求访问服务器上的数据。
- 支持 RESTful 风格服务,是构建 RESTful 服务的理想选择。
- WebAPI 后台有一系列方法(接口),供其他项目类型使用。
数据格式
| 格式 | 说明 |
|---|---|
| 纯文本 | text/plain |
| JSON | text/json(目前流行,占用带宽少) |
| XML | text/xml(WebService 技术中常用) |
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,本质是键值对的集合。
{
"name": "张三",
"age": 20,
"fav": ["读书", "写字"]
}
请求与响应的数据格式
- 客户端 → 服务器:URL 格式(IP + 端口 + 资源路径 + 携带的参数)
- 服务器 → 客户端(响应):JSON 或 XML
客户端 / 服务器
- 服务器:WebAPI 项目,运行后提供数据服务(对应接口)
- 客户端:WinForm 项目、WPF 项目、浏览器等
二、HTTP 基础(理论)
HTTP 与 HTTPS
- HTTP(超文本传输协议):简单的请求-响应协议,运行在 TCP 之上。指定了客户端能发送什么消息、得到什么响应。
- HTTPS:以安全为目标的 HTTP 通道,在 HTTP 基础上通过传输加密 + 身份认证保证传安全。在 HTTP 与 TCP 之间加入 SSL(安全套接层)。
URL 与 URI
- URI(统一资源标识符):用来定位服务器一个地址的标识。
- URL:一种特殊类型的 URI,包含查找某个资源所需的完整信息。
URL 组成示例:
http://www.aspxfans.com:8080/news/index.aspx?boardID=5&ID=24618&page=1#name
| 部分 | 示例 |
|---|---|
| 协议 | http: |
| 域名 | www.aspxfans.com |
| 端口 | 8080 |
| 虚拟目录 | /news/ |
| 文件名 | index.aspx |
| 参数 | ?boardID=5&ID=24618&page=1 |
| 锚点 | #name |
查询字符串格式:?key1=val1&key2=val2
MIME 媒体类型
MIME 简单理解就是资源(数据)的后缀名,如图片、文本、音频、视频的类型标识。
三、请求方式与状态码(理论)
常用 HTTP 请求方式
| 方式 | 用途 | 安全性 |
|---|---|---|
| GET | 查询/获取数据 | 参数拼 URL,不安全 |
| POST | 提交/添加数据 | 参数在请求体,相对安全 |
| PUT | 修改/编辑数据 | 参数在请求体 |
| DELETE | 删除数据 | — |
不同点:GET 请求可直接在浏览器访问;POST / PUT / DELETE 需借助接口调试工具(如 Apifox、Postman、Swagger)。
常用 HTTP 状态码
| 状态码 | 含义 |
|---|---|
| 200 | 成功 |
| 404 | 资源未找到 |
| 500 | 服务器端错误 |
请求与响应
- 请求(Request):客户端主动向服务器要数据。包含请求头、请求体。
- 响应(Response):服务器给客户端的数据,包含响应头、响应体。
四、RESTful 风格(理论)
REST = Representational State Transfer(表述性状态传递),由 Roy Fielding 在 2000 年博士论文中提出的一种软件架构风格。
- RESTful 只是风格约定,不是语法,开发者最好遵守,也可以自定义。
- WebAPI 与 RESTful 结合:HTTP 方法对应数据库操作
GET → 查询
POST → 添加
PUT → 修改
DELETE → 删除
五、WebAPI 项目搭建(实战)
创建项目注意事项
- 选择 .NET 8.0 框架
- 顶级语句可以根据需要勾选
关键 NuGet 包(WebAPIDemo.csproj)
<ItemGroup>
<PackageReference Include="SqlSugarCore" Version="5.1.4.219" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
项目启动入口(Program.cs)
using SqlSugar;
using WebAPIDemo.Services;
var builder = WebApplication.CreateBuilder(args);
// 1. 添加控制器服务(MVC 控制器,接口都定义在控制器中)
builder.Services.AddControllers();
// 2. 添加 Swagger 提供接口调试界面
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 3. 注册数据库连接(SqlSugar 客户端)
builder.Services.AddScoped<ISqlSugarClient>(s =>
{
var configBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsetting.json", optional: true, reloadOnChange: true);
IConfigurationRoot configurationRoot = configBuilder.Build();
string? str = configurationRoot.GetConnectionString("ConnectString");
SqlSugarClient Db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = str,
DbType = DbType.SqlServer,
IsAutoCloseConnection = true
});
return Db;
});
// 4. 注册服务:IStudentService 接口 → StudentService 实现
builder.Services.AddScoped<IStudentService, StudentService>();
var app = builder.Build();
// 开发环境下启用 Swagger
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection(); // HTTPS 重定向
app.UseAuthentication(); // 使用授权认证
app.MapControllers(); // 映射控制器(注册路由)
app.Run(); // 启动应用
配置文件(appsettings.json)
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ConnectString": "Server=.,1344;database=Dome;uid=sa;pwd=123456"
}
}
连接字符串通过
GetConnectionString("ConnectString")读取。
六、定义接口——控制器(实战)
控制器是 WebAPI 定义接口的核心。本项目的核心控制器为 StudentController。
控制器基本写法
[ApiController] // 标记为控制器,具备路由功能
[Route("/api/[Controller]")] // 定义路由前缀,[Controller] 会自动替换为类名 → /api/Student
public class StudentController : ControllerBase
{
private IStudentService _s1;
// 构造函数注入服务
public StudentController(IStudentService s1, ISqlSugarClient db)
{
_s1 = s1;
}
}
控制器必须继承
ControllerBase,通过构造函数注入(依赖注入)所需服务。
GET 接口(查询)
注意方法修饰符必须为
public
[HttpGet("GetStudent")] // http://localhost:5273/api/Student/GetStudent?id=2
public Student? GetStudent(int id)
{
return _s1.GetStudents().Find(s => s.Id == id);
}
[HttpGet("GetStudent1/{id}")] // 友好 URL 传参:http://localhost:5273/api/Student/GetStudent/2
public Student? GetStudent1(int id)
{
return _s1.GetStudents().Find(s => s.Id == id);
}
[HttpGet("GetStudent2")]
public Student? GetStudent2([FromQuery] int id) // 显式指明从查询字符串取值
{
return _s1.GetStudents().Find(s => s.Id == id);
}
POST 接口(提交)
[HttpPost("post1")] // 无参 post
public Student? Post1()
{
return _s1.GetStudents().Find(s => s.Id == 1);
}
[HttpPost("post2")] // 参数放在请求体
public Student? Post2([FromBody] int id)
{
return _s1.GetStudents().Find(s => s.Id == id);
}
[HttpPost("post3")] // 同时使用 body 和 query 参数
public Student? Post3([FromBody] string sex, [FromQuery] string name1)
{
return _s1.GetStudents().Find(s => s.Name == name1);
}
[HttpPost("post4")] // body 传对象
public Student? Post4([FromBody] Stu s1, [FromQuery] string name1)
{
return _s1.GetStudents().Find(s => s.Name == name1);
}
PUT 接口(修改)
[HttpPut("put1")]
public Student Put1([FromQuery] int id, [FromBody] string name)
{
Student stu = _s1.GetStudents().Find(s => s.Id == id);
stu.Name = name;
return stu;
}
DELETE 接口(删除)
[HttpDelete("d1")] // http://localhost:5273/api/Student/d1?id=1
public List<Student> d1(int id)
{
List<Student> list = _s1.GetStudents();
Student ss = list.Find(s => s.Id == id);
list.Remove(ss);
return list;
}
[HttpDelete("d2/{id}")] // 路由参数
public List<Student> d2(int id)
{
List<Student> list = _s1.GetStudents();
Student ss = list.Find(s => s.Id == id);
list.Remove(ss);
return list;
}
🎯 传参方式核心总结
FromQuery 与 FromBody 决定请求参数出现在 URL 的哪里:
| 绑定方式 | 适用请求 | 位置 | 安全性 |
|---|---|---|---|
[FromQuery] | GET | ?id=2&name=3 | 不安全 |
[FromBody] | POST/PUT | 请求体 | 相对安全 |
路由(路径)参数:{id} 这种占位符方式,如 api/Student/GetStudent/2。
接口设计考虑几个方面:
- 请求方式(GET/POST/PUT/DELETE)
- 接口路由路径拼接
- 传参方式:请求体(相对安全)、路径参数(占位符,不安全)、查询字符串(不安全)
- 同步接口和异步接口
规律:查询可用查询字符串或路径传参(不涉及安全性);提交、修改、删除有危险性,建议用请求体
[FromBody]传参。
七、WebAPI 使用 SqlSugar(实战)
1. 安装 SqlSugar
在项目中通过 NuGet 安装 SqlSugarCore 包。
2. 注册 SqlSugar 客户端
见 Program.cs 中的 AddScoped<ISqlSugarClient>,通过 ConnectionConfig 配置数据库类型、连接字符串,并设置为自动关闭连接。
builder.Services.AddScoped<ISqlSugarClient>(s =>
{
SqlSugarClient Db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = configuration.GetConnectionString("ConnectString"),
DbType = DbType.SqlServer,
IsAutoCloseConnection = true // 设为 true 免手动 Close
});
return Db;
});
3. 服务层注入并使用数据库
接口(IStudentService.cs)
public interface IStudentService
{
List<Student> GetStudents();
}
实现(StudentService.cs)
public class StudentService : IStudentService
{
private ISqlSugarClient _db;
public StudentService(ISqlSugarClient db) // 构造函数注入数据库对象
{
_db = db;
}
public List<Student> GetStudents()
{
// _db.Queryable<Student>() // 可通过 SqlSugar 查询数据库
return new List<Student>()
{
new Student(){Id=1,Name="张三"},
new Student(){Id=2,Name="张三"},
new Student(){Id=3,Name="张三"},
};
}
}
模型(Model/Student.cs)
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
依赖注入(DI):在
Program.cs用AddScoped<IStudentService, StudentService>()注册,控制器构造函数中注入IStudentService。
八、客户端调用 WebAPI(实战)
C# 其他项目类型(WinForm / WPF / Console)调用 WebAPI 一般有两种方案:
| 方案 | 说明 |
|---|---|
| HttpClient | 较新方案,推荐使用 |
| WebRequest | 较老的方案,不推荐 |
使用 HttpClient
步骤框架
- 定义请求接口地址
- 准备参数(对象序列化为 JSON)
- 序列化对象:
JsonConvert.SerializeObject(model) - 发起请求:
POST/PUT/DELETE用StringContent包裹数据 - 获取请求结果:
response.Content.ReadAsStringAsync()
完整示例代码
using System.Net.Http;
using System.Text;
class Program
{
static HttpClient client = new HttpClient(); // 创建一个客户端对象
static void Main(string[] args)
{
// GET 请求
GetAsync1("http://localhost:5273/api/Student/GetStudent/1");
GetAsync1("http://localhost:5273/api/Student/GetStudent1?id=2");
// POST 请求 —— 传递整型(直接传数字)
HttpContent content = new StringContent("2", Encoding.UTF8, "application/json");
GetPost("http://localhost:5273/api/Student/post2", content);
// POST 请求 —— 传递字符串 + 查询参数
HttpContent content1 = new StringContent("\"男\"", Encoding.UTF8, "application/json");
GetPost("http://localhost:5273/api/Student/post3?name1=张三", content1);
// POST 请求 —— 传递 JSON 对象 + 查询参数
string s3 = "{\"name\":\"zz\",\"age\":0}";
HttpContent content3 = new StringContent(s3, Encoding.UTF8, "application/json");
GetPost("http://localhost:5273/api/Student/post4?name1=张三", content3);
// PUT 请求
HttpContent content4 = new StringContent("\"明天8点40到\"", Encoding.UTF8, "application/json");
GetPut("http://localhost:5273/api/Student/put1?id=1", content4);
// DELETE 请求
GetDelete("http://localhost:5273/api/Student/d1?id=1", null);
Console.ReadLine();
}
// GET 请求方法
static async Task GetAsync1(string url)
{
var result = await client.GetAsync(url); // 异步 get 请求
result.EnsureSuccessStatusCode(); // 确保请求成功
var s = await result.Content.ReadAsStringAsync(); // 获取响应字符串
Console.WriteLine(s);
// 可用第三方库(如 Newtonsoft.Json)解析返回的 json 字符串
}
// POST 请求方法
static async Task GetPost(string url, HttpContent content)
{
var result = await client.PostAsync(url, content);
result.EnsureSuccessStatusCode();
Console.WriteLine(await result.Content.ReadAsStringAsync());
}
// PUT 请求方法
static async Task GetPut(string url, HttpContent content)
{
var result = await client.PutAsync(url, content);
result.EnsureSuccessStatusCode();
Console.WriteLine(await result.Content.ReadAsStringAsync() + "put");
}
// DELETE 请求方法
static async Task GetDelete(string url, HttpContent content)
{
var result = await client.DeleteAsync(url);
result.EnsureSuccessStatusCode();
Console.WriteLine(await result.Content.ReadAsStringAsync() + "Delete");
}
}
关键 API 说明
| 方法 | 作用 |
|---|---|
client.GetAsync(url) | 发送异步 GET 请求 |
client.PostAsync(url, content) | 发送异步 POST 请求 |
client.PutAsync(url, content) | 发送异步 PUT 请求 |
client.DeleteAsync(url) | 发送异步 DELETE 请求 |
result.EnsureSuccessStatusCode() | 若状态不是成功则抛出异常 |
result.Content.ReadAsStringAsync() | 读取响应内容字符串 |
new StringContent(json, Encoding.UTF8, "application/json") | 构造请求体(数据 + 编码 + MIME 类型) |
重要:StringContent 的三个参数
- 第 1 个:要提交的数据(JSON 字符串)
- 第 2 个:数据的编码格式
Encoding.UTF8 - 第 3 个:请求数据的格式(MIME)
application/json
HttpClient 扩展方法(命名空间 System.Net.Http.Json)
除了手动用 StringContent + SerializeObject 打包/解析 JSON,还可以使用 System.Net.Http.Json 提供的扩展方法,自动完成 JSON 序列化与反序列化,更简洁。
| 序号 | 方法 | 作用 |
|---|---|---|
| 1 | client.PostAsJsonAsync(url, obj) | 发送 POST 请求,自动把对象序列化为 JSON 放到请求体 |
| 2 | client.PutAsJsonAsync(url, obj) | 发送 PUT 请求,自动序列化对象为 JSON |
| 3 | client.GetFromJsonAsync<Student>(url) | 发送 GET 请求,并自动把响应反序列化为指定类型 |
| 4 | response.ReadFromJsonAsync<Student>() | 读取请求结果(HttpResponseMessage),并反序列化为指定类型 |
| 5 | client.DeleteFromJsonAsync<T>(url) | 发送 DELETE 请求,并自动反序列化响应(可选) |
示例代码:
using System.Net.Http;
using System.Net.Http.Json;
class Program
{
static HttpClient client = new HttpClient();
static async Task Main()
{
// 1. POST 请求:直接传对象,自动序列化为 JSON
var sendData = new { Id = 4, Name = "李四" };//匿名对象
await client.PostAsJsonAsync("http://localhost:5273/api/Student/post4?name1=张三", sendData);
// 2. GET 请求:自动反序列化响应为 List<Student>
var list = await client.GetFromJsonAsync<List<Student>>(
"http://localhost:5273/api/Student/getStudents");
// 3. POST 后读取响应并反序列化
HttpResponseMessage resp =
await client.PostAsJsonAsync("http://localhost:5273/api/Student/post4?name1=张三", stu);
Student result = await resp.ReadFromJsonAsync<Student>();
}
}
说明:
- 使用前需要
using System.Net.Http.Json;。 GetFromJsonAsync<T>()是一次性 GET + 反序列化。ReadFromJsonAsync<T>()对已拿到的HttpResponseMessage做反序列化,可配合PostAsync/PostAsJsonAsync等使用。

6594

被折叠的 条评论
为什么被折叠?



