.Net之接口小知识
目的
通过一个简单的项目,在原来的文章基础上完善一下常用的几种WebApi编写方式以及请求方式,一方面是用于给我一个前端朋友用来学习调用接口,另一方面让我测试HttpClient的一些效果。
本文示例代码环境:vs2022、net6
准备
新创建了一个.Net WebAPI程序,安装组件
<ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
    <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.3.1" />
</ItemGroup>
ConfigureServices配置NewtonsoftJson以及Automapper和操作数据库代码(为了省事,删除了一些不影响当前效果的代码)
public void ConfigureServices(IServiceCollection services)
{
	services.AddControllers().AddNewtonsoftJson();
    services.AddEndpointsApiExplorer();
	services.AddSwaggerGen(c =>
	{
		c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyWebApi", Version = "v1" });
	});
	//注入AutoMapper
	services.AddAutoMapper(Assembly.GetExecutingAssembly().DefinedTypes.Where(t => typeof(Profile).GetTypeInfo()
	.IsAssignableFrom(t.AsType())).Select(t => t.AsType()).ToArray());
}
注意:在Net core3.0以后,微软移除了Newtonsoft.Json,而使用了System.Text.Json,所以依赖于Newtonsoft.Json的组件将不可用,需要安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson 包
因为仅仅作为演示,所以我只是新增一个控制器,里面包含了get、post、put、patch、delete几种类型的接口。这里先不贴代码,一点一点看。通过一个用户的添加、修改、删除作为一个演示的流程。
记得配置允许跨域请求,要不js请求会因为跨域问题而报错。详情看此处
数据来源就是控制器里面的一个静态变量,格式如下
public class UserDto
{
    public long UserId { get; set; }
    public string Name { get; set; }
    public string Sex { get; set; }
}
静态变量如下
private static readonly List<UserDto> _userDtoList = Enumerable.Range(0, 100)
        .Select(t => new UserDto
        {
            Name = "张三" + t,
            Sex = "男",
            UserId = 6974150586715897857 + t
        }).ToList();
后端请求的方法我使用的是HttpClient,并且做成了一个公共类,部分需要用到的如下
public class HttpClientHelper: IHttpHelper
{
    private readonly System.Net.Http.HttpClient _client;
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="httpClientFactory"></param>
    public HttpClientHelper(IHttpClientFactory httpClientFactory)
    {
        _client = httpClientFactory.CreateClient();
    }
    private void VerifyParam(string url, string jwtToken, IDictionary<string, string> headers)
    {
        _client.DefaultRequestHeaders.Clear();
        if (string.IsNullOrWhiteSpace(url))
        {
            throw new ArgumentNullException("url不能为null");
        }
        if (!string.IsNullOrWhiteSpace(jwtToken))
        {
            _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}");
        }
        if (headers?.Count > 0)
        {
            foreach (var (key, value) in headers)
            {
                _client.DefaultRequestHeaders.Add(key, value);
            }
        }
    }
    private static async Task<T> ConvertResponseResult<T>(HttpResponseMessage httpResponse)
    {
        //确保成功完成,不是成功就返回具体错误信息
        httpResponse.EnsureSuccessStatusCode();
        var resStr = await httpResponse.Content.ReadAsStringAsync();
        if (typeof(T) == typeof(string))
            return (T)Convert.ChangeType(resStr, typeof(string));
        return JsonConvert.DeserializeObject<T>(resStr);
    }
}
操作
请求头传递token只是为了演示请求头传递参数的写法,token为伪值
GET
从web服务检索数据。传递参数的本质是url字符串拼接,Request-Head头部传递,Request-Body中不能传递(严格点说不建议,因为我使用Apifox等工具可以在body中传值,swagger会提示 Request with GET/HEAD method cannot have body)
Query格式
编写用户id查询用户信息接口
[HttpGet("user/details")]
public UserDto GetUserDetails(long userId)
{
    if (!_userDtoList.Any(t => t.UserId == userId))
        throw new ParameterException("未找到用户标识");
    return _userDtoList.Find(t => t.UserId == userId);
}
前端请求
$(function () {
    $.ajax({
        type: "get",
        url: "http://localhost:5000/api/HttpSample/user/details?userId=6974150586715897857",
        headers: { "Authorization": "Bearer 123456" },
        contentType: "application/json",
        success: function (data, status) {
            if (status == "success") {
                console.log(JSON.stringify(data));
            }
        }
    });
    var postdata = { userId: "6974150586715897857" };
    $.ajax({
        type: "get",
        headers:{"Authorization":"Bearer 123456"},
        url: "http://localhost:5000/api/HttpSample/user/details",
        data: postdata,
        success: function (data, status) {
            if (status == "success") {
                console.log(JSON.stringify(data));
            }
        }
    });
});
后端请求
var token = "123456";//此处token是伪值
var result = await _httpHelper.GetAsync<ResultModel<UserDto>>("http://localhost:5000/api/HttpSample/user/details?userId=6974150586715897857", token);
这里的_httpHelper是注入的IHttpHelper(下面其他的方法一样),对应的GetAsync为
public async Task<T> GetAsync<T>(string url, string jwtToken = "", IDictionary<string, string> headers = null)
{
    VerifyParam(url, jwtToken, headers);
    var response = await _client.GetAsync(url).ConfigureAwait(false);
    return await ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具请求
url:http://localhost:5000/api/HttpSample/user/details?userId=6974150586715897857
并且再请求头增加:Authorization,值为Bearer xxxx
返回结果如下

POST
在web服务上创建新的数据项。约定用于向服务端提交数据操作,请求时候参数放在参数FromBody传递
Json格式
演示添加用户操作
请求类
public class UserDto
{
    public long UserId { get; set; }
    public string Name { get; set; }
    public string Sex { get; set; }
}
接口代码示例
[HttpPost("user/add")]
public bool Add([FromBody] UserDto request)
{
    if (_userDtoList.Any(t => t.UserId == request.UserId))
        throw new ParameterException("用户标识已经存在");
    Console.WriteLine(DateTime.Now + "   " + HttpContext.Request.Headers["Authorization"].FirstOrDefault());
    _userDtoList.Add(request);
    return true;
}
前端请求
$(function () {
    var param = { userId: "8974150586715897867", name: "老八", sex: "女" };
    $.ajax({
        type: "post",
        dataType: 'json',
        contentType: "application/json",
        headers: { "Authorization": "Bearer 123456" },
        url: "http://localhost:5000/api/HttpSample/user/add",
        data: JSON.stringify(param),
        success: function (data) {
            if (status == "success") {
                console.log(JSON.stringify(data));
            }
        }
    });
});
后端请求
var token = "123456";//此处token是伪值
var url = "http://localhost:5000/api/HttpSample/user/add";
var usedto = new UserDto
{
    UserId = 123456,
    Name = "李四",
    Sex = "女"
};
var result = await _httpHelper.PostAsync<ResultModel<bool>>(url, usedto, token);
public async Task<T> PostAsync<T>(string url, object data, string jwtToken = "", IDictionary<string, string> headers = null)
{
    VerifyParam(url, jwtToken, headers);
    var jsonData = data is string ? data.ToString() : JsonConvert.SerializeObject(data);
    using var content = new StringContent(jsonData ?? string.Empty, Encoding.UTF8, "application/json");
    var response = await _client.PostAsync(url, content).ConfigureAwait(false);
    return await ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具请求
传递参数格式为json格式,请求头部默认添加:"Content-Type", "application/json"

x-www-form-unlencoded格式
更新用户姓名
[HttpPost("user/updatename")]
public bool UpdateName([FromForm] long userId, [FromForm] string name)
{
    var entity = _userDtoList.Find(t => t.UserId == userId);
    if (entity is null)
        throw new ParameterException("用户标识不存在");
    entity.Name = name;
    return true;
}
前端请求
$(function () {
    var postdata = { userId: "6974150586715897857", name: "赵六" };
    $.ajax({
        type: "post",
        headers: { "Authorization": "Bearer 123456" },
        url: "http://localhost:5000/api/HttpSample/user/updatename",
        data: postdata,
        success: function (data, status) {
            if (status == "success") {
                console.log(JSON.stringify(data));
            }
        }
    });
});
后端请求
var token = "123456";//此处token是伪值
var url = "http://localhost:5000/api/HttpSample/user/updatename";
var dic = new Dictionary<string, string>
{
    { "userId","6974150586715897857"},
    { "name","王五"}
};
var result = await _httpHelper.PostFormDataAsync<ResultModel<bool>>(url, dic, token);
public async Task<T> PostFormDataAsync<T>(string url, Dictionary<string, string> data, string jwtToken = "", IDictionary<string, string> headers = null)
{
    VerifyParam(url, jwtToken, headers);
    var httpContent = new FormUrlEncodedContent(data);
    var response = await _client.PostAsync(url, httpContent).ConfigureAwait(false);
    return await ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具请求
选择post请求,参数在Body,然后选择x-www-form-unlencoded格式。

Form-data格式
模拟上传用户头像操作
[HttpPost("user/uploadImg")]
public string Upload([FromForm] IFormFile img, [FromForm] long userId)
{
    if (img is null)
        throw new ParameterException("用户头像不能为null");
    Console.WriteLine(HttpContext.Request.Headers["Authorization"].FirstOrDefault());
    var entity = _userDtoList.Find(t => t.UserId == userId);
    if (entity is null)
        throw new ParameterException("用户标识不存在");
    return img.FileName;
}
注意:当你上传大于30000000字节长度的文件时候,需要修改上传文件的默认限制
前端请求
$(function () {
    $("#tijiao").click(function () {
        //logoimg是<input type="file" id="logoimg"" />
        var files = $("#logoimg").prop('files'); //获取到文件列表
        var formData = new FormData();
        formData.append("userId", "6974150586715897857");
        formData.append("img", files[0], "1122.jpg");//图片文件流
        console.log(formData);
        $.ajax({
            type: 'post',
            url: "http://localhost:5000/api/HttpSample/user/uploadImg",
            headers: {
                "Authorization": "Bearer 123456"
            },
            mimeType: "multipart/form-data",
            processData: false,
            contentType: false,
            data: formData,
            success: function (data) {
                //后端Httpclient请求成功后返回过来的结果
                console.log(data);
            }
        });
    });
});
后端请求
var url = "http://localhost:5000/api/HttpSample/user/uploadImg";
var formData = new MultipartFormDataContent();
var bytes = System.IO.File.ReadAllBytes("D:\\Downloads\\11111.jpg");
var byteContent = new ByteArrayContent(bytes);
byteContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
    Name = "img",
    FileName = "111.jpg"
};
formData.Add(byteContent);
// 写法一
formData.Add(new StringContent("6974150586715897857"), "userId");
// 写法二
var byteContent2 = new ByteArrayContent(Encoding.UTF8.GetBytes("天气"));
byteContent2.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
    Name = "name",
};
formData.Add(byteContent2);
var headerDic = new Dictionary<string, string>
{
	{ "Authorization","Bearer 123456"},
};
var result = await _httpHelper.PostFormDataAsync<ResultModel<string>>(url, formData, headerDic);
public async Task<T> PostFormDataAsync<T>(string url, MultipartFormDataContent data, IDictionary<string, string> headers = null)
{
    VerifyParam(url, "", headers);
    var result = await _client.PostAsync(url, data).ConfigureAwait(false);
    return await ConvertResponseResult<T>(result);
}
接口工具请求
选择Body=>form-data

PUT
更新web服务上的数据项。
Json格式
更新用户信息
[HttpPut("user/update")]
public bool Update(UserDto userDto)
{
    if (userDto is null)
        throw new ParameterException("参数不能为空");
        Console.WriteLine(DateTime.Now + "    " + HttpContext.Request.Headers["Authorization"].FirstOrDefault());
        var currUser = _userDtoList.Find(t => t.UserId == userDto.UserId);
    if (currUser is null)
        throw new ParameterException("用户标识不存在");
    currUser.Name = userDto.Name;
    currUser.Sex = userDto.Sex;
    return true;
}
前端请求
$(function () {
    var param = { userId: "6974150586715897859", name: "老八", sex: "女" };
    $.ajax({
        type: "put",
        dataType: 'json',
        contentType: "application/json",
        headers: { "Authorization": "Bearer 123456" },
        url: "http://localhost:5000/api/HttpSample/user/update",
        data: JSON.stringify(param),
        success: function (data, status) {
            if (status == "success") {
                console.log(JSON.stringify(data));
            }
        }
    });
});
后端请求
var token = "123456";//此处token是伪值
var usedto = new UserDto
{
    UserId = 6974150586715897859,
    Name = "老八",
    Sex = "女"
};
var url = "http://localhost:5000/api/HttpSample/user/update";
var result = await _httpHelper.PutAsync<ResultModel<bool>>(url, usedto, token);
return JsonConvert.SerializeObject(result);
public async Task<T> PutAsync<T>(string url, object data, string jwtToken = "", IDictionary<string, string> headers = null)
{
    VerifyParam(url, jwtToken, headers);
    var jsonData = data is string ? data.ToString() : JsonConvert.SerializeObject(data);
    using var content = new StringContent(jsonData ?? string.Empty, Encoding.UTF8, "application/json");
    var response = await _client.PutAsync(url, content).ConfigureAwait(false);
    return await ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具请求
URL:http://localhost:5000/api/HttpSample/user/update
参数传递:Body=>json

DELETE
删除web服务上的数据项。
Query格式
删除用户信息
[HttpDelete("user")]
public bool Delete(long userId)
{
    var entity = _userDtoList.Find(t => t.UserId == userId);
    if (entity is null)
        throw new ParameterException("用户标识不存在");
    Console.WriteLine(DateTime.Now + "    " + HttpContext.Request.Headers["Authorization"].FirstOrDefault());
    _userDtoList.Remove(entity);
    return true;
}
前端请求
$(function () {
    $.ajax({
        type: "DELETE",
        url: "http://localhost:5000/api/HttpSample/user?userId=6974150586715897861",
        headers: { "Authorization": "Bearer 123456" },
        success: function (data, status) {
            if (status == "success") {
                console.log(JSON.stringify(data));
            }
        }
    });
});
后端请求
var token = "123456";//此处token是伪值
var url = "http://localhost:5000/api/HttpSample/user?userId=6974150586715897862";
var result = await _httpHelper.DeleteAsync<ResultModel<bool>>(url, token);
public async Task<T> DeleteAsync<T>(string url, string jwtToken = "", IDictionary<string, string> headers = null)
{
    VerifyParam(url, jwtToken, headers);
    var response = await _client.DeleteAsync(url).ConfigureAwait(false);
    return await ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具请求
URL:http://localhost:5000/api/HttpSample/user?userId=6974150586715897859

Patch
通过描述有关如何修改项的一组说明,更新web服务上的数据项。
请求格式如下:
[{"op" : "replace", "path" : "/PassWord", "value" : "222222"}]
op属性指示操作的类型,path属性指示要更新的元素,value属性提供新值。
add:添加属性或数组元素。 对于现有属性:设置值。
remove:删除属性或数组元素。
replace:替换操作
为了支持该请求方式,需要安装nuget包Microsoft.AspNetCore.Mvc.NewtonsoftJson。
参考文档:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/jsonpatch?view=aspnetcore-6.0
Json格式
在此用于更新数据
[HttpPatch("user/update2/{userId}")]
public UserDto Update2([FromRoute] long userId, JsonPatchDocument<UserDto> jsonPatch, [FromServices] IMapper mapper)
{
    var entity = _userDtoList.Find(t => t.UserId == userId);
    if (entity is null)
        throw new ParameterException("用户标识无效");
    var dto = mapper.Map<UserDto>(entity);
    jsonPatch.ApplyTo(dto, ModelState);
    var user = _userDtoList.Find(t => t.UserId == userId);
    mapper.Map(dto, user);
    return user;
}
前端请求
演示根据用户id去更新用户的姓名
$(function () {
    var par = [{ "op": "replace", "path": "/name", "value": "老六" }];
    $.ajax({
        type: "Patch",
        url: "http://localhost:5000/api/HttpSample/user/update2/6974150586715897857",
        headers: { "Authorization": "Bearer 123456" },
        contentType: "application/json",
        data: JSON.stringify(par),
        success: function (result) {
            console.log(result);
        }
    });
});
后端请求
var token = "123456";//此处token是伪值
var url = "http://localhost:5000/api/HttpSample/user/update2/6974150586715897859";
var content = "[{\"op\":\"replace\",\"path\":\"/name\",\"value\":\"小七七\"}]";
var result = await _httpHelper.PatchAsync<ResultModel<UserDto>>(url, content, token);
public async Task<T> PatchAsync<T>(string url, object data, string jwtToken = "", IDictionary<string, string> headers = null)
{
    VerifyParam(url, jwtToken, headers);
    var jsonData = data is string ? data.ToString() : JsonConvert.SerializeObject(data);
    using var content = new StringContent(jsonData ?? string.Empty, Encoding.UTF8, "application/json");
    var response = await _client.PatchAsync(url, content).ConfigureAwait(false);
    return await ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具请求
参数传递:Body=>json

.Net之接口小知识的更多相关文章
- 【C#小知识】C#中一些易混淆概念总结(四)---------解析Console.WriteLine()                                                       分类:            C#             2014-02-05 17:18    1060人阅读    评论(0)    收藏
		目录: [C#小知识]C#中一些易混淆概念总结 [C#小知识]C#中一些易混淆概念总结(二) [C#小知识]C#中一些易混淆概念总结(三) ------------------------------ ... 
- Java基础小知识(一)
		序言:“不积跬步,无以至千里.不积小流,无以成江海.”每一个庞大的知识架构都是由无数个小知识点慢慢积累起来的,没有量变的积累,就没有质变上的飞跃,成功往往离不开积累. 今天就和大家分享一些我在学习J ... 
- Autofac 依赖注入小知识
		Autofac 依赖注入小知识 控制反转/依赖注入 IOC/DI 依赖接口而不依赖于实现,是面向对象的六大设计原则(SOLID)之一.即依赖倒置原则(Dependence Inversion Prin ... 
- 蓝牙Bluetooth技术小知识
		蓝牙Bluetooth技术以及广泛的应用于各种设备,并将继续在物联网IoT领域担任重要角色.下面搜集整理了一些关于蓝牙技术的小知识,以备参考. 蓝牙Bluetooth技术始创于1994年,其名字来源于 ... 
- HTML+CSS中的一些小知识
		今天分享一些HTML.CSS的小知识,希望能够对大家有所帮助! 1.解决网页乱码的问题:最重要的是要保证各个环节的字符编码一致! (1)编辑器的编辑环境的字符集(默认字符集):Crtl+U 常见的编码 ... 
- iOS APP开发的小知识(分享)
		亿合科技小编发现从2007年第一款智能手机横空出世,由此开启了人们的移动智能时代.我们从一开始对APP的陌生,到现在的爱不释手,可见APP开发的出现对我们的生活改变有多巨大.而iOS AP ... 
- Unix系统小知识(转)
		Unix操作系统的小知识 2.VI添加行号/翻页/清屏 .在对话模式时(即输完Esc再输入: ),输入“:set number”可以将编辑的文本加上行号.跟玩俄罗斯方块一样方便的上下左右移动箭头的快捷 ... 
- salesforce 零基础开发入门学习(十)IDE便捷小知识
		在这里介绍两个IDE的便捷开发的小知识. 一) 本地调试 由于salesforce代码只能提交以后才能调试,所以很多时候调试代码很麻烦.新版增加了一个特性:即可以在本地调试相关的代码或者查看相关代码运 ... 
- Jquery:小知识;
		Jquery:小知识: jQuery学习笔记(二):this相关问题及选择器 上一节的遗留问题,关于this的相关问题,先来解决一下. this的相关问题 this指代的是什么 这个应该是比较好理 ... 
随机推荐
- Android高仿网易云音乐-启动界面实现和动态权限处理
			效果 实现分析 基本上没有什么难点,就是布局,然后显示用户协议对话框,动态处理权限,判断是否显示引导界面,是否显示广告界面等. 布局 <?xml version="1.0" ... 
- C语言中限定符的作用
			C语言中常用的一般包括const.static.extern.register和volatile这几个.这些是C语言标准中规定的关键词,所有的编译器都必须支持这些关键词,它们的作用如下: 1.cons ... 
- C语言项目实现顺序表
			#include <stdio.h> #include <stdlib.h> #include "test_顺序表声明.h" /* run this pro ... 
- MQ系列2:消息中间件的技术选型
			1 背景 在高并发.高消息吞吐的互联网场景中,我们经常会使用消息队列(Message Queue)作为基础设施,在服务端架构中担当消息中转.消息削峰.事务异步处理 等职能. 对于那些不需要实时响应的的 ... 
- umask计算创建文件、目录的默认权限
			很多人以为 创建文件默认权限就是 666-umask=创建文件的默认权限 创建目录的默认权限就是 777-umask=创建目录的默认权限 这种计算其实是不严谨的 为什么我们创建的文件的权限是 64 ... 
- Rails_via牛客网
			题目 链接:https://ac.nowcoder.com/acm/contest/28537/D 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言 ... 
- nodejs学习总结01
			主流渲染引擎介绍1.渲染引擎又叫 排版引擎 或 浏览器内核 .(双内核:执行html和css的)2,主流的渲染引擎有**Chrome浏览器**:Blink引壁(WebKit的一个分支)**Safari ... 
- 使用flex弹性布局代替传统浮动布局来为微信小程序写自适应页面
			原文转载自「刘悦的技术博客」https://v3u.cn/a_id_109 我们知道,写习惯了前端的人,一般切图后布局页面的话,上手最习惯的是基于盒子模型的浮动布局,依赖 display 属性 + p ... 
- java-Servlet编码/异常处理
			1. Servlet输出中文(1)为什么会有乱码?out.println方法在输出时或者表单提交的时候,浏览器会对表单中的中文参数值进行编码; 注:会使用表单所在的页面打开时使用的编码方式进行编码服务 ... 
- 一文理解Hadoop分布式存储和计算框架入门基础
			@ 目录 概述 定义 发展历史 发行版本 优势 生态项目 架构 组成模块 HDFS架构 YARN架构 部署 部署规划 前置条件 部署步骤 下载文件(三台都执行) 创建目录(三台都执行) 配置环境变量( ... 
