RestSharp 简介
官方:RestSharp 可能是.NET 最流行的 HTTP 客户端库。它具有自动序列化和反序列化、请求和响应类型检测、多种身份验证和其他有用功能,正被数十万个项目使用。
RestSharp 的主要目的是通过 HTTP 对远程资源进行同步和异步调用。顾名思义,RestSharp 的主要受众是使用 REST API 的开发人员。只要您具有要发送的资源 URI 和请求参数符合 W3C HTTP 标准,RestSharp 就 可以通过 HTTP 调用任何 API。
由于 WMS 会出现作为 HTTP 客户端去调用 API 的场景,所以就用到了 RestSharp。之前本人有自己封装过一个简单的 HttpClient 库,也使用了一段时间,但是考虑到后续需求的多样性,所以还是使用了 RestSharp 进行开发,项目中我也对其进行了简单的二次封装,方便使用。
关于 RestSharp 的快速上手,这里我就不赘述了,官方提供了很详细的文档,建议大家自行学习使用,下面我会介绍 WMS 中对 RestSharp 的二次封装和使用,另外也说明下使用过程中遇到的各种坑。
RestSharp 二次封装
封装位置
在进行封装前,先考虑将其封装哪一层,这里我们既然将其封装为一个通用工具,让每个项目都可以使用,自然也就考虑放在Wpf.MvvmLight.SelfHost.Common这一层了。
安装包
打开Wpf.MvvmLight.SelfHost.Common项目后,可以通过 nuget 包管理工具直接搜索"RestSharp"进行包的安装,也可以使用 IDE 或命令行来进行包的安装:
dotnet add package RestSharp
开始封装
添加完 RestSharp 包后,接下来就可以进入正式的封装工作了。这里我对 RestSharp 进行了泛型和非泛型的两种封装,每种封装内分别提供了同步和异步方法,可供大家参考使用,如果有其他的需求,同样也可在此封装的基础上继续进行拓展。
非泛型封装
public class RangeRestApi
{
#region 同步
public string Get(string url, object pars = null)
{
var type = Method.Get;
RestResponse reval = GetApiInfo(url, pars, type);
return reval.Content;
}
public string Post(string url, object pars = null)
{
var type = Method.Post;
RestResponse reval = GetApiInfo(url, pars, type);
return reval.Content;
}
public string Delete(string url, object pars = null)
{
var type = Method.Delete;
RestResponse reval = GetApiInfo(url, pars, type);
return reval.Content;
}
public string Put(string url, object pars = null)
{
var type = Method.Put;
RestResponse reval = GetApiInfo(url, pars, type);
return reval.Content;
}
private static RestResponse GetApiInfo(string url, object pars, Method type)
{
var request = new RestRequest();
request.Method = type;
if (pars != null)
{
request.AddObject(pars);
}
var client = new RestClient(url);
RestResponse reval = client.Execute(request);
if (reval.ErrorException != null)
{
throw new Exception($"{type}请求出错:{reval.ErrorException.Message}");
}
return reval;
}
#endregion
#region 异步
public async Task<string> GetAsync(string url, object pars = null)
{
var type = Method.Get;
RestResponse reval = await GetApiInfoAsync(url, pars, type);
return reval.Content;
}
public async Task<string> PostAsync(string url, object pars = null)
{
var type = Method.Post;
RestResponse reval = await GetApiInfoAsync(url, pars, type);
return reval.Content;
}
public async Task<string> DeleteAsync(string url, object pars = null)
{
var type = Method.Delete;
RestResponse reval = await GetApiInfoAsync(url, pars, type);
return reval.Content;
}
public async Task<string> PutAsync(string url, object pars = null)
{
var type = Method.Put;
RestResponse reval = await GetApiInfoAsync(url, pars, type);
return reval.Content;
}
private static async Task<RestResponse> GetApiInfoAsync(string url, object pars, Method type)
{
var request = new RestRequest();
request.Method = type;
if (pars != null)
{
request.AddObject(pars);
}
var client = new RestClient(url);
RestResponse reval = await client.ExecuteAsync(request);
if (reval.ErrorException != null)
{
throw new Exception($"{type}请求出错:{reval.ErrorException.Message}");
}
return reval;
}
泛型封装
public class RangeRestApi<T> where T : class, new()
{
#region 同步
public T Get(string url, object pars = null)
{
var type = Method.Get;
RestResponse<T> reval = GetApiInfo(url, pars, type);
return reval.Data;
}
public T Post(string url, object pars = null)
{
var type = Method.Post;
RestResponse<T> reval = GetApiInfo(url, pars, type);
return reval.Data;
}
public T Delete(string url, object pars = null)
{
var type = Method.Delete;
RestResponse<T> reval = GetApiInfo(url, pars, type);
return reval.Data;
}
public T Put(string url, object pars = null)
{
var type = Method.Put;
RestResponse<T> reval = GetApiInfo(url, pars, type);
return reval.Data;
}
private static RestResponse<T> GetApiInfo(string url, object pars, Method type)
{
var request = new RestRequest();
request.Method = type;
if (pars != null)
{
request.AddObject(pars);
}
var client = new RestClient(url);
RestResponse<T> reval = client.Execute<T>(request);
if (reval.ErrorException != null)
{
throw new Exception($"{type}请求出错:{reval.ErrorException.Message}");
}
return reval;
}
#endregion
#region 异步
public async Task<T> GetAsync(string url, object pars = null)
{
var type = Method.Get;
RestResponse<T> reval = await GetApiInfoAsync(url, pars, type);
return reval.Data;
}
public async Task<T> PostAsync(string url, object pars = null)
{
var type = Method.Post;
RestResponse<T> reval = await GetApiInfoAsync(url, pars, type);
return reval.Data;
}
public async Task<T> DeleteAsync(string url, object pars = null)
{
var type = Method.Delete;
RestResponse<T> reval = await GetApiInfoAsync(url, pars, type);
return reval.Data;
}
public async Task<T> PutAsync(string url, object pars = null)
{
var type = Method.Put;
RestResponse<T> reval = await GetApiInfoAsync(url, pars, type);
return reval.Data;
}
private static async Task<RestResponse<T>> GetApiInfoAsync(string url, object pars, Method type)
{
var request = new RestRequest();
request.Method = type;
if (pars != null)
{
request.AddObject(pars);
}
var client = new RestClient(url);
RestResponse<T> reval = await client.ExecuteAsync<T>(request);
if (reval.ErrorException != null)
{
throw new Exception($"{type}请求出错:{reval.ErrorException.Message}");
}
return reval;
}
#endregion
}
开始使用
封装完成后,即可在项目中进行使用,下面提供了发送 Post 和 Get 异步请求的两种实例(同框架中实例):
private async Task SendPostRequest()
{
var response = await new RangeRestApi().PostAsync("http://127.0.0.1:9000/api/v1/home/echo", new { name = "Range post" });
EventSignal.SendWriteDebugLogSignal($"获取POST请求响应:{response}");
}
private async Task SendGetRequest()
{
var response = await new RangeRestApi().GetAsync("http://127.0.0.1:9000/api/v1/home/echo", new { name = "Range get" });
EventSignal.SendWriteDebugLogSignal($"获取GET请求响应:{response}");
}
遇坑与填坑
总希望一切工作都可以顺利进行,但总是事与愿违,这次同样也不例外。
1.System.Net.Http 版本包问题
遇坑:一切封装和开发工作完成后,启动项目报错:
方法System.Net.Http.CloneableExtensions.Clone: 类型参数"System.Net.Http.Headers.MediaTypeHeaderValue"与类型参数"T"的约束冲突。
原因:项目在.NET 4.6.1 框架下集成了 SelfHost,而 SelfHost 中用到的 Web Api 的包与项目中的其他包产生了版本冲突。
填坑:提供两种解决方法供参考,第一,将项目中的 Nuget 包 System.Net.Http 更新到 4.3.1 版本以上即可;第二(不推荐),更改项目下 App.config 文件中的配置:
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
2.System.ValueTuple 版本包问题
遇坑:一切封装和开发工作完成后,项目正常启动,但是通过 RestSharp 发送 Web 请求时,抛出异常:
未能加载文件或程序集"System.ValueTuple, Version=4.0.2.0,Culture=neutral......"
原因:RestSharp 中需要的 System.ValueTuple 包版本与当前项目.NET 4.6.1 框架下提供的该包版本不匹配。
填坑:提供两种解决方法供参考,第一,将 System.ValueTuple 包升级/降级到 4.3.0 版本即可;第二(不推荐),修改 App.config 文件中的配置,注释掉绑定重定向标签即可(或者直接修改版本):
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<!--<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />-->
</dependentAssembly>
3.可能遇到的其他版本包问题
上面两个坑是我项目开发中遇到的,如果有遇到类似上面的其他版本包问题,填坑方法也是类似的。