main
wanggaofeng 1 year ago
parent ae12d952d4
commit 198b90bda3

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HttpClientStudy.Core
{
public class HandlerA : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//请求前业务
var response = await base.SendAsync(request, cancellationToken);
//响应后业务
return response;
}
}
}

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HttpClientStudy.Core
{
public class HandlerB : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
InnerHandler = new SocketsHttpHandler() { };
//请求前业务
var response = await base.SendAsync(request, cancellationToken);
//响应后业务
return response;
}
}
}

@ -18,4 +18,8 @@
<ProjectReference Include="..\HttpClientStudy.Model\HttpClientStudy.Model.csproj" /> <ProjectReference Include="..\HttpClientStudy.Model\HttpClientStudy.Model.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="RequestContents\" />
</ItemGroup>
</Project> </Project>

@ -35,7 +35,7 @@ namespace HttpClientStudy.Core
public void AddDelegatingHandler(DelegatingHandler handler) public void AddDelegatingHandler(DelegatingHandler handler)
{ {
this.HttpMessageHandlers.Add(handler); HttpMessageHandlers.Add(handler);
} }
public HttpClient CreateHttpClient() public HttpClient CreateHttpClient()

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Polly; using Polly;
using Polly.Utilities; using Polly.Utilities;

@ -29,40 +29,10 @@ namespace HttpClientStudy.UnitTest
HttpClient httpClient = new HttpClient(handler); HttpClient httpClient = new HttpClient(handler);
var sd = await httpClient.GetAsync("http://127.0.0.1"); var sd = await httpClient.GetAsync(TestConfig.WebApiBaseUrl + "/api/");
var contentText = await sd.Content.ReadAsStringAsync(); var contentText = await sd.Content.ReadAsStringAsync();
_logger.WriteLine(contentText); _logger.WriteLine(contentText);
} }
} }
public class HandlerB : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken)
{
InnerHandler = new SocketsHttpHandler() { };
//请求前业务
var response = await base.SendAsync(request, cancellationToken);
//响应后业务
return response;
}
}
public class HandlerA : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//请求前业务
var response = await base.SendAsync(request, cancellationToken);
//响应后业务
return response;
}
}
} }

@ -12,8 +12,11 @@ global using Xunit.Internal;
global using Xunit.Serialization; global using Xunit.Serialization;
global using HttpClientStudy.Model; global using HttpClientStudy.Model;
global using HttpClientStudy.Core; global using HttpClientStudy.Core;
global using HttpClientStudy.Service; global using HttpClientStudy.Service;
global using HttpClientStudy.WebApp; global using HttpClientStudy.WebApp;
global using HttpClientStudy.WebApp.Models; global using HttpClientStudy.WebApp.Models;
global using HttpClientStudy.WebApp.Controllers; global using HttpClientStudy.WebApp.Controllers;

@ -6,10 +6,9 @@ using System.Security.Cryptography.Xml;
using System.Text; using System.Text;
using System.Text.Unicode; using System.Text.Unicode;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace HttpClientStudy.UnitTest namespace HttpClientStudy.UnitTest.HttpClients
{ {
/// <summary> /// <summary>
/// 高级Get请求 测试 /// 高级Get请求 测试

@ -13,7 +13,7 @@ using System.Security.Authentication.ExtendedProtection;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Text.Json.Serialization.Metadata; using System.Text.Json.Serialization.Metadata;
namespace HttpClientStudy.UnitTest namespace HttpClientStudy.UnitTest.HttpClients
{ {
/// <summary> /// <summary>
/// HttpClient 常见问题测试 /// HttpClient 常见问题测试

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace HttpClientStudy.UnitTest namespace HttpClientStudy.UnitTest.HttpClients
{ {
public class PipelineClientTest public class PipelineClientTest
{ {

@ -1,10 +1,4 @@
using System; namespace HttpClientStudy.UnitTest.HttpClients
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HttpClientStudy.UnitTest.Core
{ {
/// <summary> /// <summary>
/// SimpleHttpClient 测试类 /// SimpleHttpClient 测试类

@ -1,511 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http.Json;
using System.Net;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Security.Authentication.ExtendedProtection;
using Newtonsoft.Json.Linq;
using System.Text.Json.Serialization.Metadata;
namespace HttpClientStudy.UnitTest
{
/// <summary>
/// 基础HttpClient 测试
/// </summary>
public class SimpleHttpClientTest
{
private readonly ITestOutputHelper _logger;
public SimpleHttpClientTest(ITestOutputHelper outputHelper)
{
_logger = outputHelper;
}
#region GET请求
[Fact]
public async Task GetAllAccounts_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var responseMessage = await httpClient.GetAsync("/api/Normal/GetAllAccounts");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<List<Account>>>();
Assert.IsType<BaseResult<List<Account>>>(result);
Assert.Equal(1, result.Code);
Assert.NotNull(result.Data);
}
/// <summary>
/// GET 请求
/// (默认参数方式url传参)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetAccount_Id_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccount?Id=2");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal(2, result.Data?.Id);
}
/// <summary>
/// GET 请求
/// (路由传参)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetAccount_Route_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccount/管理员02");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal("管理员02", result.Data?.Name);
}
/// <summary>
/// GET 请求
/// (中文参数:现在浏览器直接支持,为最大兼容老旧浏览器使用url编码)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetAccountByName_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var ChineseName = System.Net.WebUtility.UrlEncode("管理员01");
var ChineseName2 = System.Net.WebUtility.UrlEncode("管理员02");
//现在浏览器直接支持中文参数
//var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountByName?ChineseName=管理员01&ChineseName2=管理员02");
//兼容老浏览器写法
var responseMessage = await httpClient.GetAsync($"/api/Normal/GetAccountByName?ChineseName={ChineseName}&ChineseName2={ChineseName2}");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<List<Account>>>();
Assert.IsType<BaseResult<List<Account>>>(result);
Assert.Equal(1, result.Code);
Assert.Equal(2, result.Data?.Count);
}
/// <summary>
/// GET 请求
/// (查询参数传参)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetAccountByRole_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountByRole?role=Admin");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<List<Account>>>();
Assert.IsType<BaseResult<List<Account>>>(result);
Assert.Equal(1, result.Code);
//每项的角色都是查询的角色
Assert.False(result.Data?.Any(d=>d.Role != "Admin"));
}
/// <summary>
/// GET 请求
/// (请求头传参中文必须Url编码,服务端Url解码后使用)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetAccountFromHeader_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
//中文参数必须先编码
httpClient.DefaultRequestHeaders.Add("name", System.Net.WebUtility.UrlEncode("管理员01"));
var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountFromHeader");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal(1,result.Data?.Id);
}
/// <summary>
/// GET 请求
/// (客户端不传参服务端参数直接来由IoC中注入的服务)
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetAccountByService_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountFromServices");
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal("服务注入示例",result.Data?.Name);
}
/// <summary>
/// GET 请求
/// (直接调用System.Net.Http.Json类的扩展方法GetFromJsonAsync 获取 Json 结果)
/// </summary>
/// <returns></returns>
[Fact]
public async Task Get_From_Json_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var result = await httpClient.GetFromJsonAsync<BaseResult<Account>>("/api/Normal/GetAccountFromServices");
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal("服务注入示例", result.Data?.Name);
}
#endregion
#region PUT 请求
/// <summary>
/// Put 请求
/// (新建或替换、更新资源)
/// </summary>
/// <returns></returns>
[Fact]
public async Task PutDemo_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var responseMessage = await httpClient.PutAsync("/api/Normal/PutDemo?id=2",null);
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadAsStringAsync();
}
#endregion
#region HEAD 请求
/// <summary>
/// Head 请求
/// 注意HttpClient没有直接提供HEAD请求方法
/// 步骤1构建 HttpRequestMessage 对象设置HttpMethod.Head
/// 步骤2把上步构建的HttpRequestMessage 对象,作为参数传递给 HttpClient实例的 Send 或 SendAsync 方法
/// </summary>
/// <returns></returns>
[Fact]
public async Task HeadDemo_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var requestMessage = new HttpRequestMessage(HttpMethod.Head, "/api/Normal/HeadDemo?Id=2");
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
//head请求没有返回体
var result = await responseMessage.Content.ReadAsStringAsync();
Assert.Empty(result);
}
#endregion
#region POST 请求
[Fact]
public async Task PostSimple_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
//响应
var responseMessage = await httpClient.PostAsync("/api/Normal/PostSimple", null);
//响应正常
Assert.True(responseMessage.IsSuccessStatusCode);
Assert.NotNull(responseMessage);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<string>>();
Assert.IsType<BaseResult<string>>(result);
Assert.Equal(1, result?.Code);
}
[Fact]
public async Task PostCreate_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
//参数
var para = new Account() {Id=100, Name="小明", Password="123456", Role="Admin" };
//请求体
var plainContent = new StringContent(JsonConvert.SerializeObject(para), Encoding.UTF8, System.Net.Mime.MediaTypeNames.Application.Json);
//发POST请求
var responseMessage = await httpClient.PostAsync("/api/Normal/PostCreate", plainContent);
//确保响应正常
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var text = await responseMessage.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<CreatedAtActionResult> (text);
Assert.IsType<CreatedAtActionResult>(result);
Assert.Equal(201, result.StatusCode);
Assert.IsType<Newtonsoft.Json.Linq.JObject>(result.Value);
//新创建的对象
var account = JsonConvert.DeserializeObject<Account>(value: result.Value.ToString() ?? "");
Assert.NotNull(account);
Assert.Equal(100,account.Id);
//由于构造函数等原因直接使用ReadFromJsonAsync会异常。
//CreatedAtActionResult? result = await responseMessage.Content.ReadFromJsonAsync<CreatedAtActionResult>(new JsonSerializerOptions() { IncludeFields=true, PropertyNameCaseInsensitive=true});
}
[Fact]
public async Task PostUpdate_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
//参数
var para = new Account() { Id = 1, Name = "小明", Password = "123456", Role = "Admin" };
//发POST请求
var responseMessage = await httpClient.PostAsJsonAsync("/api/Normal/PostUpdate", para);
//确保响应正常
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal(1, result.Data?.Id);
}
[Fact]
public async Task PostRemove_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var para_id = 2;
//发POST请求(URL传参)
var responseMessage = await httpClient.PostAsync($"/api/Normal/PostRemove?Id={para_id}", null);
//确保响应正常
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
Assert.Equal(para_id, result.Data?.Id);
}
#endregion
#region DELETE 请求
[Fact]
public async Task Delete_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var para_id = 2;
//发POST请求(URL传参)
var responseMessage = await httpClient.DeleteAsync($"/api/Normal/Delete?Id={para_id}");
//确保响应正常
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<int>>();
Assert.IsType<BaseResult<int>>(result);
Assert.Equal(1, result.Code);
Assert.Equal(para_id, result.Data);
}
[Fact]
public async Task Delete2_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var account = new Account() { Id = 2, Name = "小明", Password = "123456", Role = "Admin" };
var requestMessage = new HttpRequestMessage(HttpMethod.Delete, "/api/Normal/DeleteForJsonData");
//Delete 默认不使用请求体如果使用的话需要Content配合 RequestMessage
requestMessage.Content = JsonContent.Create(account);
//也可以下面的,极少有使用(可自定义JsonSerializerOptions)
//requestMessage.Content = JsonContent.Create(account,JsonTypeInfo.CreateJsonTypeInfo<Account>( JsonSerializerOptions.Default),new System.Net.Http.Headers.MediaTypeHeaderValue("application/json","utf-8"));
//发Delete请求(带json请求体)
var responseMessage = await httpClient.SendAsync(requestMessage);
//确保响应正常
responseMessage.EnsureSuccessStatusCode();
Assert.NotNull(responseMessage);
Assert.True(responseMessage.IsSuccessStatusCode);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
Assert.IsType<BaseResult<Account>>(result);
Assert.Equal(1, result.Code);
}
#endregion
#region OPTIONS 请求
[Fact]
public async Task OPTIONS_Test()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
};
var requestMessage = new HttpRequestMessage(HttpMethod.Options, "/api/Normal/OptionsSimple");
//响应
var responseMessage = await httpClient.SendAsync(requestMessage);
//响应正常
Assert.True(responseMessage.IsSuccessStatusCode);
Assert.NotNull(responseMessage);
var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<string>>();
Assert.IsType<BaseResult<string>>(result);
Assert.Equal(1, result?.Code);
}
#endregion
#region PATCH 请求
#endregion
#region TRACE 请求
#endregion
#region CONNECT 请求
#endregion
}
}

@ -5,11 +5,11 @@ namespace HttpClientStudy.UnitTest
/// <summary> /// <summary>
/// 使用 xUnit 单元测试框架 /// 使用 xUnit 单元测试框架
/// </summary> /// </summary>
public class UseXunit public class UseXunitTest
{ {
private readonly ITestOutputHelper _logger; private readonly ITestOutputHelper _logger;
public UseXunit(ITestOutputHelper outputHelper) public UseXunitTest(ITestOutputHelper outputHelper)
{ {
_logger = outputHelper; _logger = outputHelper;
} }

@ -1,4 +1,4 @@
namespace HttpClientStudy.UnitTest.WebApp namespace HttpClientStudy.UnitTest
{ {
public class BaseResultTest public class BaseResultTest
{ {

Loading…
Cancel
Save