RestClient 库提供了一个简单的连接器来使用 REST 服务。
要在项目中使用它,请将 Mafe.RestClient NuGet 包添加到您的项目中。
RestClient 的目标是使开发人员能够以非常简单的方式轻松连接到任何服务器。只需定义您的数据传输对象 (Dto) 并开始与客户端一起玩!
使用 Build() 方法从 Rest 创建 RestBuilder:
var rest = Rest . Build ( ) ;
要创建一个简单的 get 调用,只需这样做:
var rest = Rest . Build ( ) ;
var result = rest . Url ( "[URL]" ) . Get ( ) ;
或者我们可以使用 GetAsync() 方法:
var rest = Rest . Build ( ) ;
var result = await rest . Url ( "[URL]" ) . GetAsync ( ) ;
每当您在本文档中找到“[URL]”一词时,它都指的是 webAPI 的基本 URL 定义。
我们可以定义一个 Root() 端点并使用它来构建请求。
public RestBuilder Root ( ) => rest . Url ( "https://mywebapi.mydomain.com" ) ;
然后,我们可以使用它,如下所示:
public RestBuilder Root ( ) => Rest . Build ( ) . Url ( "https://mywebapi.mydomain.com" ) ;
var result = Root ( )
. Command ( "/my-action" )
. Payload ( "mystring" )
. Post ( ) ;
使用 RestProperties 配置您的休息根点。要创建一个简单的配置,就像这样:
RestProperties properties = new RestProperties
{
EndPoint = new Uri ( "[URL]" ) , //if you use .Url("[URL]") you override it
BufferSize = 4096 ,
CertificateOption = ClientCertificateOption . Manual ,
Timeout = TimeSpan . FromMinutes ( 2 )
} ;
使用带有属性的 Build() 方法从 Rest 创建 RestBuilder:
var rest = Rest . Build ( properties ) ;
X.509 证书的验证对于创建不易受到中间人攻击的安全 SSL/TLS 会话至关重要。
证书链验证包括以下步骤:
不建议通过实施自定义证书链验证来重新发明轮子。
TLS 库提供了应该使用的内置证书验证函数。
List < string > validCerts = new List < string > ( ) {
"CERT STRING"
} ;
var result = Rest . Build ( )
. CertificateValidation ( ( sender , certificate , chain , errors ) =>
{
// for development, trust all certificates
if ( development ) return true ;
// Compliant: trust only some certificates
return errors == SslPolicyErrors . None
&& validCerts . Contains ( certificate . GetCertHashString ( ) ) ;
} )
. Url ( "[URL]" )
. Get ( ) ;
根据 HTTP/1.1 [RFC2617] 的定义,应用程序应直接在授权请求标头中发送 access_token。您可以通过在 HTTP 请求正文中包含不记名令牌的 access_token 值作为“授权:不记名 {access_token_value}”来实现此目的。
如果经过身份验证的用户的不记名令牌的 access_token 或 refresh_token 已过期,则会返回“401 - 未经授权(刷新令牌无效或过期)”错误。
var result = Rest . Build ( )
. Authentication ( ( ) => new AuthenticationHeaderValue ( "Bearer" , "[Token]" ) )
. Url ( "[URL]" )
. Get ( ) ;
有效的承载令牌(具有活动的 access_token 或 refresh_token 属性)可以使用户的身份验证保持活动状态,而不需要他或她经常重新输入其凭据。 access_token 只要处于活动状态即可使用,即登录或续订后最多一小时。 fresh_token 的有效期为 336 小时(14 天)。 access_token 过期后,可以使用活动的refresh_token 来获取新的access_token/refresh_token 对,如以下示例所示。此周期最多可持续 90 天,之后用户必须再次登录。如果refresh_token过期,则无法更新token,用户必须重新登录。
要刷新令牌,请自动使用“RefreshTokenInvoke”。
var url = "[URL]" ;
var result = Rest . Build ( )
. Authentication ( ( ) => new AuthenticationHeaderValue ( "Bearer" , "[Token]" ) )
. RefreshToken ( true )
. RefreshTokenInvoke ( async ( ) =>
{
var result = await rest
. Url ( url )
. Command ( "/refresh" )
. GetAsync < TokenObjectResponse > ( ) ;
doSomethings ( ) ; //store the token inside your env.
return result ;
} )
. Command ( "/detail" )
. Url ( url )
. Get ( ) ;
应该撤销refresh_token:
NetworkCredential 类是一个基类,它在基于密码的身份验证方案(例如基本、摘要、NTLM 和 Kerberos)中提供凭据。实现 ICredentials 接口的类(例如 CredentialCache 类)返回 NetworkCredential 对象。此类不支持基于公钥的身份验证方法,例如安全套接字层 (SSL) 客户端身份验证。
var result = Rest . Build ( )
. NetworkCredential ( "myUsername" , "myPassword" )
. Url ( "[URL]" )
. Get ( ) ;
var result = rest
. NetworkCredential ( ( ) => new System . Net . NetworkCredential ( "myUsername" , "myPassword" ) )
. Url ( "[URL]" )
. Get ( ) ;
Headers 集合包含与请求关联的协议标头。 Header((h)=>{}) 方法允许您添加键列表。
var result = Rest . Build ( )
. Header ( ( h ) => {
if ( ! h . Contains ( "auth-custom" ) )
h . Add ( "auth-custom" , "value" ) ;
} )
. Url ( "[URL]" )
. Get ( ) ;
RestClient 支持两种类型的序列化:Xml 和 Json,但可以实现 ISerializerContent 来自定义序列化。 RestClient 使用 .Json() 将对象序列化为 json。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Json ( )
. Get < ResponseObject > ( ) ;
可以将 json 序列化器选项传递给 .Json() 方法,如下所示:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Json ( new JsonSerializerOptions {
WriteIndented = true
} )
. Get < ResponseObject > ( ) ;
上面的代码片段考虑使用 System.Text.Json 库。如果我们像这样使用 Netwnsoft:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Json ( new JsonSerializerSettings {
Formatting = Formatting . Indented
} )
. Get < ResponseObject > ( ) ;
RestClient 使用 .Xml() 将对象序列化为 xml。
var result = rest
. Url ( "[URL]" )
. Xml ( )
. Get < ResponseObject > ( ) ;
可以将设置传递给 .Xml() 方法,如下所示:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Xml ( new XmlReaderSettings { Indent = true } , new XmlWriterSettings { IgnoreWhitespace = true } )
. Get < ResponseObject > ( ) ;
下面的示例介绍了如何通过实现 ISerializerContent 接口来执行自定义序列化:
public class MyCustomSerializer : ISerializerContent
{
public string MediaTypeAsString => throw new NotImplementedException ( ) ;
public object DeserializeObject ( string value , Type typeOf , object options = null )
{
throw new NotImplementedException ( ) ;
}
public string SerializeObject ( object value , Type typeOf , object options = null )
{
throw new NotImplementedException ( ) ;
}
}
现在,我们可以像这样使用 MyCustomSerializer:
var result = Rest . Build ( )
. Url ( "[URL]" )
. CustomSerializer ( new MyCustomSerializer { } )
. Get < ResponseObject > ( ) ;
BufferSize 可用于设置上传和下载流期间的缓冲区大小。默认值为 80Kb
var result = Rest . Build ( )
. Url ( "[URL]" )
. BufferSize ( 4096 * 5 * 5 ) //100Kb
. Get ( ) ;
在与指定资源通信期间启用 gzip 压缩:
var result = Rest . Build ( )
. Url ( "[URL]" )
. EnableGZipCompression ( )
. Get ( ) ;
库自动解压缩响应。
GET 是最常见的 HTTP 方法之一,GET 用于向指定资源请求数据
var rest = Rest . Build ( ) ;
var result = rest
. Url ( "[URL]" )
. Get ( ) ;
var result = await rest
. Url ( "[URL]" )
. GetAsync ( ) ;
关于 GET 请求的其他一些注意事项:
请注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的。
在某些情况下,我们需要使用参数作为查询字符串。我们可以使用 Parameter(key, value) 方法来解析它,如下所示:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/path" )
. Parameter ( "id" , "10" )
. Parameter ( "type" , "myType" )
. Get ( ) ;
生成的url为:[URL]/path?id=10&type=myType
POST 用于将数据发送到服务器以创建/更新资源。通过 POST 发送到服务器的数据存储在 HTTP 请求的请求负载中:
var rest = Rest . Build ( ) ;
var result = rest
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. Post < ResponseObject > ( ) ;
var result = await rest
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. PostAsync < ResponseObject > ( ) ;
Post 是另一种常见的 http 方法,用于:
PUT 用于将数据发送到服务器以创建/更新资源。
POST 和 PUT 之间的区别在于 PUT 请求是幂等的。也就是说,多次调用相同的 PUT 请求将始终产生相同的结果。相反,重复调用 POST 请求会产生多次创建相同资源的副作用。
var rest = Rest . Build ( ) ;
var result = rest
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. Put < ResponseObject > ( ) ;
var result = await rest
. Url ( "[URL]" )
. Payload ( new Object { } )
. PutAsync < ResponseObject > ( ) ;
DELETE 方法删除指定的资源。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. Delete < ResponseObject > ( ) ;
var result = await Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. DeleteAsync < ResponseObject > ( ) ;
DOWNLOAD方法下载指定的资源。
var result = Rest . Build ( )
. Download ( "[URL]" ) ;
var result = await rest
. DownloadAsync ( "[URL]" ) ;
可以使用 OnDownloadProgress 显示下载状态。
var rest = Rest . Build ( ) ;
var result = await rest
. OnDownloadProgress ( ( d ) => Console . WriteLine ( $ " { d . CurrentBytes } / { d . TotalBytes } " ) )
. DownloadAsync ( "[URL]" ) ;
传播应取消操作的通知。
CancellationToken 支持线程、线程池工作项或任务对象之间的协作取消。您可以通过实例化 CancellationTokenSource 对象来创建取消令牌,该对象管理从其 CancellationTokenSource 检索的取消令牌。
以下示例使用取消令牌来停止执行:
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource ( ) ;
CancellationToken token = source . Token ;
// Schedules a cancel operation on this System.Threading.CancellationTokenSource
// after the specified number of milliseconds
token . CancelAfter ( 3000 ) ;
var file1 = Rest . Build ( ) . DownloadAsync ( "[URL FILE1]" , token . Token ) ;
var file2 = Rest . Build ( ) . DownloadAsync ( "[URL FILE2]" , token . Token ) ;
var get1 = Rest . Build ( ) . Url ( "[URL GET1]" ) . GetAsync < MyObject > ( token . Token ) ;
Task . WaitAll ( file1 , file2 , get1 ) ;
取消请求后,它会抛出 TaskCancellatedException。异常将被封装到 RestResult 对象中。
自定义指定资源的 CUSTOM 方法。
HttpMethod PATCH = new HttpMethod ( "PATCH" ) ;
var rest = Rest . Build ( ) ;
var result = rest
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. CustomCall < ResponseObject > ( PATCH ) ;
var result = await rest
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new Object { } )
. CustomCallAsync < ResponseObject > ( PATCH ) ;
RestClient 使用 Playload(obj) 方法根据请求设置对象:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new RequestObject { } )
. Post < ResponseObject > ( ) ;
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. Payload ( new RequestObject { } )
. Put < ResponseObject > ( ) ;
必要时我们可以使用表单 url 编码的请求。要使用它,我们需要启用它,如下所示:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. EnableFormUrlEncoded ( true )
然后我们可以将参数作为字典传递:
var params = new Dictionary < string , string > ( ) ;
params . Add ( "key1" , "value1" ) ;
params . Add ( "key2" , "value2" ) ;
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. EnableFormUrlEncoded ( true )
. FormUrlEncoded ( params )
. Post ( ) ;
可以在处理程序内部传递参数并启用表单 URL 编码:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. FormUrlEncoded ( true , ( p ) =>
{
p . Add ( "key1" , "value1" ) ;
p . Add ( "key2" , "value2" ) ;
} )
. Post ( ) ;
OnUploadProgress 在请求正在运行且数据即将传出时发生。我们可以获得上传数据的百分比,如下所示:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnUploadProgress ( p =>
{
DoSomethings ( p . ProgressPercentage ) ;
} ) //occurs during request
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnDownloadProgress 在响应运行且数据传入时发生。我们可以像这样获取正在下载的数据的百分比:
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnDownloadProgress ( p =>
{
DoSomethings ( p . ProgressPercentage ) ;
} ) //occurs during response
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
默认值为 100,000 毫秒(100 秒)。要设置无限超时,请将属性值设置为 InfiniteTimeSpan。域名系统 (DNS) 查询最多可能需要 15 秒才能返回或超时。如果您的请求包含需要解析的主机名,并且您将 Timeout 设置为小于 15 秒的值,则可能需要 15 秒或更长时间才会引发异常以指示您的请求超时。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Timeout ( 3200 ) //milliseconds
. Get < ResponseObject > ( ) ;
var result = Rest . Build ( )
. Url ( "[URL]" )
. Timeout ( TimeSpan . FromMinutes ( 10 ) )
. Get < ResponseObject > ( ) ;
OnStart 是请求开始时触发的事件。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnStart ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnPreviewContentRequestAsString 是一个在请求准备就绪且尚未发送时触发的事件。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnPreviewContentRequestAsString ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnPreviewContentResponseAsString 是在收到响应且尚未反序列化时触发的事件。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnPreviewContentResponseAsString ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnPreResult 在请求正在完成但尚未完成时发生。当 OnPreResult 引发时,我们可以做一些事情,例如获取并使用请求的结果。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnPreCompleted ( ( r ) => {
DoSomethings ( r . Result ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnException 当请求引发异常时发生。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnException ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnCompleted 在请求完成时发生。
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnCompleted ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
RestClient 允许创建灵活且健壮的网络层,并且非常易于使用。下面您可以找到完整的代码演示完整的代码示例。
public class NetworkService {
//building context
public RestBuilder Root ( )
=> Rest . Build ( )
. CertificateValidation ( ( sender , certificate , chain , errors ) =>
{
if ( development ) return true ;
return errors == SslPolicyErrors . None
&& validCerts . Contains ( certificate . GetCertHashString ( ) ) ;
} )
. Url ( "[URL]" ) ;
public RestBuilder RootAuthentication ( )
=> Root ( )
. Authentication ( ( ) => new AuthenticationHeaderValue ( "Bearer" , "[Token]" ) )
. RefreshToken ( )
. RefreshTokenInvoke ( async ( ) => await PostRefreshAsync ( new RefreshRequest { } ) ) ;
public RestBuilder UsersRoot ( )
=> Root ( ) . Command ( "/Users" ) ;
public RestBuilder DimensionsRoot ( )
=> Root ( ) . Command ( "/Dimensions" ) ;
public RestBuilder EventsRoot ( )
=> RootAuthentication ( ) . Command ( "/Events" ) ;
//requests
public async Task < RestResult < LoginResponse > > PostLoginAsync ( LoginRequest request )
=> await UsersRoot ( )
. Command ( "/Login" ) //[URL]/Users/Login
. Payload ( request )
. PostAsync < LoginResponse > ( ) ;
public async Task < RestResult < RuleResponse > > GetRulesAsync ( )
=> await UsersRoot ( )
. Command ( "/Rules" )
. GetAsync < RuleResponse > ( ) ;
public async Task < RestResult < RefreshResponse > > PostRefreshAsync ( RefreshRequest request )
=> await UsersRoot ( )
. Command ( "/Refresh" )
. Payload ( request )
. PostAsync < RefreshResponse > ( ) ;
public async Task < RestResult < CountryResponse > > PostCountriesAsync ( CountryRequest request )
=> await DimensionsRoot ( )
. Command ( "/Countries" )
. Payload ( request )
. PostAsync < CountryResponse > ( ) ;
public async Task < RestResult < EventDetailResponse > > PostEventDetailAsync ( EventDetailRequest request )
=> await EventsRoot ( )
. Command ( "/EventDetail" )
. Payload ( request )
. PostAsync < EventDetailResponse > ( ) ;
}