c#软件开发学习笔记--WebAPI

WebAPI 学习总结

目录


一、什么是 WebAPI(理论)

Web API = Web Application Programming Interface(网络应用程序接口)。

  • 基于 HTTP 协议的网络应用程序接口,使用 JSON 或 XML 格式传输数据。
  • 服务器端应用程序,允许客户端通过 HTTP 请求访问服务器上的数据。
  • 支持 RESTful 风格服务,是构建 RESTful 服务的理想选择。
  • WebAPI 后台有一系列方法(接口),供其他项目类型使用。

数据格式

格式说明
纯文本text/plain
JSONtext/json(目前流行,占用带宽少)
XMLtext/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;
}

🎯 传参方式核心总结

FromQueryFromBody 决定请求参数出现在 URL 的哪里:

绑定方式适用请求位置安全性
[FromQuery]GET?id=2&name=3不安全
[FromBody]POST/PUT请求体相对安全

路由(路径)参数{id} 这种占位符方式,如 api/Student/GetStudent/2

接口设计考虑几个方面

  1. 请求方式(GET/POST/PUT/DELETE)
  2. 接口路由路径拼接
  3. 传参方式:请求体(相对安全)、路径参数(占位符,不安全)、查询字符串(不安全)
  4. 同步接口和异步接口

规律:查询可用查询字符串或路径传参(不涉及安全性);提交、修改、删除有危险性,建议用请求体 [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.csAddScoped<IStudentService, StudentService>() 注册,控制器构造函数中注入 IStudentService


八、客户端调用 WebAPI(实战)

C# 其他项目类型(WinForm / WPF / Console)调用 WebAPI 一般有两种方案:

方案说明
HttpClient较新方案,推荐使用
WebRequest较老的方案,不推荐

使用 HttpClient

步骤框架
  1. 定义请求接口地址
  2. 准备参数(对象序列化为 JSON)
  3. 序列化对象JsonConvert.SerializeObject(model)
  4. 发起请求POST/PUT/DELETEStringContent 包裹数据
  5. 获取请求结果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 序列化与反序列化,更简洁。

序号方法作用
1client.PostAsJsonAsync(url, obj)发送 POST 请求,自动把对象序列化为 JSON 放到请求体
2client.PutAsJsonAsync(url, obj)发送 PUT 请求,自动序列化对象为 JSON
3client.GetFromJsonAsync<Student>(url)发送 GET 请求,并自动把响应反序列化为指定类型
4response.ReadFromJsonAsync<Student>()读取请求结果(HttpResponseMessage),并反序列化为指定类型
5client.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 等使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值