La bibliothèque RestClient fournit un connecteur simple pour consommer les services REST.
Pour l'utiliser dans votre projet, ajoutez le package Mafe.RestClient NuGet à votre projet.
L'objectif de RestClient est de permettre aux développeurs de se connecter facilement à n'importe quel serveur de manière très simple. Définissez simplement votre objet de transfert de données (Dto) et commencez à jouer avec le client !
Utilisez la méthode Build() pour créer un RestBuilder à partir de Rest :
var rest = Rest . Build ( ) ;
Pour créer un appel simple, procédez comme ceci :
var rest = Rest . Build ( ) ;
var result = rest . Url ( "[URL]" ) . Get ( ) ;
ou nous pouvons utiliser la méthode GetAsync() :
var rest = Rest . Build ( ) ;
var result = await rest . Url ( "[URL]" ) . GetAsync ( ) ;
Chaque fois que vous trouvez le mot « [URL] » dans ce document, il fait référence à la définition de l'URL de base de l'API Web.
Nous pouvons définir un point de terminaison Root() et l'utiliser pour créer la requête.
public RestBuilder Root ( ) => rest . Url ( "https://mywebapi.mydomain.com" ) ;
et puis, on peut l'utiliser, comme ceci :
public RestBuilder Root ( ) => Rest . Build ( ) . Url ( "https://mywebapi.mydomain.com" ) ;
var result = Root ( )
. Command ( "/my-action" )
. Payload ( "mystring" )
. Post ( ) ;
Pour utiliser RestProperties pour configurer votre point racine de repos. Pour créer une configuration simple, comme ceci :
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 )
} ;
Utilisez la méthode Build() avec des propriétés pour créer un RestBuilder à partir de Rest :
var rest = Rest . Build ( properties ) ;
La validation des certificats X.509 est essentielle pour créer des sessions SSL/TLS sécurisées et non vulnérables aux attaques de l'homme du milieu.
La validation de la chaîne de certificats comprend les étapes suivantes :
Il n'est pas recommandé de réinventer la roue en mettant en œuvre une validation de chaîne de certificats personnalisée.
Les bibliothèques TLS fournissent des fonctions de validation de certificat intégrées qui doivent être utilisées.
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 ( ) ;
Comme défini par HTTP/1.1 [RFC2617], l'application doit envoyer le access_token directement dans l'en-tête de la demande d'autorisation. Vous pouvez le faire en incluant la valeur access_token du jeton du porteur dans le corps de la requête HTTP sous la forme « Autorisation : porteur {access_token_value} ».
Si un utilisateur authentifié dispose d'un access_token ou d'un jeton d'actualisation d'un jeton de support qui a expiré, une erreur « 401 - Non autorisé (jeton d'actualisation invalide ou expiré) » est renvoyée.
var result = Rest . Build ( )
. Authentication ( ( ) => new AuthenticationHeaderValue ( "Bearer" , "[Token]" ) )
. Url ( "[URL]" )
. Get ( ) ;
Un jeton de porteur valide (avec les propriétés access_token ou rafraîchir_token actives) maintient l'authentification de l'utilisateur sans l'obliger à ressaisir fréquemment ses informations d'identification. Le access_token peut être utilisé aussi longtemps qu'il est actif, soit jusqu'à une heure après la connexion ou le renouvellement. Lefresh_token est actif pendant 336 heures (14 jours). Après l'expiration du access_token, un rafraîchissement_token actif peut être utilisé pour obtenir une nouvelle paire access_token / rafraîchissement_token, comme indiqué dans l'exemple suivant. Ce cycle peut se poursuivre jusqu'à 90 jours, après quoi l'utilisateur doit se reconnecter. Si le rafraîchissement_token expire, les jetons ne peuvent pas être renouvelés et l'utilisateur doit se reconnecter.
Pour actualiser un jeton, utilisez automatiquement « 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 ( ) ;
Un rafraîchissement_token doit être révoqué :
La classe NetworkCredential est une classe de base qui fournit des informations d'identification dans les schémas d'authentification par mot de passe tels que basic, digest, NTLM et Kerberos. Les classes qui implémentent l'interface ICredentials, telles que la classe CredentialCache, renvoient des objets NetworkCredential. Cette classe ne prend pas en charge les méthodes d'authentification basées sur une clé publique telles que l'authentification client SSL (Secure Sockets Layer).
var result = Rest . Build ( )
. NetworkCredential ( "myUsername" , "myPassword" )
. Url ( "[URL]" )
. Get ( ) ;
var result = rest
. NetworkCredential ( ( ) => new System . Net . NetworkCredential ( "myUsername" , "myPassword" ) )
. Url ( "[URL]" )
. Get ( ) ;
La collection Headers contient les en-têtes de protocole associés à la demande. La méthode Header((h)=>{}) permet d'ajouter la liste des clés.
var result = Rest . Build ( )
. Header ( ( h ) => {
if ( ! h . Contains ( "auth-custom" ) )
h . Add ( "auth-custom" , "value" ) ;
} )
. Url ( "[URL]" )
. Get ( ) ;
Deux types de sérialisation sont pris en charge par RestClient : Xml et Json, mais il est possible d'implémenter ISerializerContent pour personnaliser la sérialisation. RestClient utilise .Json() pour sérialiser un objet en json.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Json ( )
. Get < ResponseObject > ( ) ;
Il est possible de passer les options d'un sérialiseur json à la méthode .Json(), comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Json ( new JsonSerializerOptions {
WriteIndented = true
} )
. Get < ResponseObject > ( ) ;
L'extrait de code ci-dessus envisage d'utiliser la bibliothèque System.Text.Json. Si nous utilisons Netwnsoft comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Json ( new JsonSerializerSettings {
Formatting = Formatting . Indented
} )
. Get < ResponseObject > ( ) ;
RestClient utilise .Xml() pour sérialiser un objet en XML.
var result = rest
. Url ( "[URL]" )
. Xml ( )
. Get < ResponseObject > ( ) ;
Il est possible de passer les paramètres à la méthode .Xml(), comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Xml ( new XmlReaderSettings { Indent = true } , new XmlWriterSettings { IgnoreWhitespace = true } )
. Get < ResponseObject > ( ) ;
Ci-dessous, un exemple sur la façon dont vous pouvez effectuer une sérialisation personnalisée en implémentant l'interface 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 ( ) ;
}
}
Maintenant, nous pouvons utiliser MyCustomSerializer comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. CustomSerializer ( new MyCustomSerializer { } )
. Get < ResponseObject > ( ) ;
BufferSize peut être utilisé pour définir la taille du tampon pendant le téléchargement et le flux de téléchargement. La valeur par défaut est 80 Ko
var result = Rest . Build ( )
. Url ( "[URL]" )
. BufferSize ( 4096 * 5 * 5 ) //100Kb
. Get ( ) ;
Active la compression gzip lors de la communication avec une ressource spécifiée :
var result = Rest . Build ( )
. Url ( "[URL]" )
. EnableGZipCompression ( )
. Get ( ) ;
La bibliothèque décompresse automatiquement la réponse.
GET est l'une des méthodes HTTP les plus courantes et GET est utilisé pour demander des données à une ressource spécifiée.
var rest = Rest . Build ( ) ;
var result = rest
. Url ( "[URL]" )
. Get ( ) ;
var result = await rest
. Url ( "[URL]" )
. GetAsync ( ) ;
Quelques autres notes sur les requêtes GET :
Notez que la chaîne de requête (paires nom/valeur) est envoyée dans l'URL d'une requête GET.
Dans certains cas, nous devons utiliser des arguments comme chaîne de requête. Nous pouvons utiliser la méthode Parameter(key, value) pour le résoudre comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/path" )
. Parameter ( "id" , "10" )
. Parameter ( "type" , "myType" )
. Get ( ) ;
L'url générée est : [URL]/path?id=10&type=myType
POST est utilisé pour envoyer des données à un serveur pour créer/mettre à jour une ressource. Les données envoyées au serveur avec POST sont stockées dans la charge utile de la requête 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 est une autre méthode http courante, utilisée pour :
PUT est utilisé pour envoyer des données à un serveur pour créer/mettre à jour une ressource.
La différence entre POST et PUT est que les requêtes PUT sont idempotentes. Autrement dit, appeler plusieurs fois la même requête PUT produira toujours le même résultat. En revanche, l’appel répété d’une requête POST a pour effet secondaire de créer plusieurs fois la même ressource.
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 > ( ) ;
La méthode DELETE supprime la ressource spécifiée.
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 > ( ) ;
La méthode DOWNLOAD télécharge la ressource spécifiée.
var result = Rest . Build ( )
. Download ( "[URL]" ) ;
var result = await rest
. DownloadAsync ( "[URL]" ) ;
Est-il possible d'afficher l'état du téléchargement avec OnDownloadProgress.
var rest = Rest . Build ( ) ;
var result = await rest
. OnDownloadProgress ( ( d ) => Console . WriteLine ( $ " { d . CurrentBytes } / { d . TotalBytes } " ) )
. DownloadAsync ( "[URL]" ) ;
Propage une notification indiquant que les opérations doivent être annulées.
Un CancellationToken permet une annulation coopérative entre les threads, les éléments de travail du pool de threads ou les objets Task. Vous créez un jeton d'annulation en instanciant un objet CancellationTokenSource, qui gère les jetons d'annulation récupérés à partir de son CancellationTokenSource.
L'exemple suivant utilise un jeton d'annulation pour arrêter l'exécution :
// 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 ) ;
Après l'annulation demandée, il lève une TaskCancellatedException. L'exception sera encapsulée dans l'objet RestResult.
Méthode CUSTOM personnalisant la ressource spécifiée.
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 utilise la méthode Playload(obj) pour définir un objet sur demande :
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 > ( ) ;
Si nécessaire, nous pouvons utiliser la demande sous forme d'URL de formulaire codée. Pour l'utiliser, nous devons l'activer, comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. EnableFormUrlEncoded ( true )
et ensuite nous pouvons passer les paramètres sous forme de dictionnaire :
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 ( ) ;
Il est possible de passer les paramètres à l'intérieur du gestionnaire et d'activer le form-url-codé :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. FormUrlEncoded ( true , ( p ) =>
{
p . Add ( "key1" , "value1" ) ;
p . Add ( "key2" , "value2" ) ;
} )
. Post ( ) ;
OnUploadProgress se produit lorsque la requête est en cours d'exécution et que les données sont sortantes. Nous pouvons obtenir un pourcentage des données téléchargées comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnUploadProgress ( p =>
{
DoSomethings ( p . ProgressPercentage ) ;
} ) //occurs during request
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnDownloadProgress se produit lorsque la réponse est en cours d'exécution et que les données arrivent. Nous pouvons obtenir un pourcentage des données en cours de téléchargement comme ceci :
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnDownloadProgress ( p =>
{
DoSomethings ( p . ProgressPercentage ) ;
} ) //occurs during response
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
La valeur par défaut est 100 000 millisecondes (100 secondes). Pour définir un délai d'expiration infini, définissez la valeur de la propriété sur InfiniteTimeSpan. Une requête DNS (Domain Name System) peut prendre jusqu'à 15 secondes pour être renvoyée ou expirer. Si votre demande contient un nom d'hôte qui nécessite une résolution et que vous définissez Timeout sur une valeur inférieure à 15 secondes, cela peut prendre 15 secondes ou plus avant qu'une exception ne soit levée pour indiquer un délai d'attente sur votre demande.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Timeout ( 3200 ) //milliseconds
. Get < ResponseObject > ( ) ;
var result = Rest . Build ( )
. Url ( "[URL]" )
. Timeout ( TimeSpan . FromMinutes ( 10 ) )
. Get < ResponseObject > ( ) ;
OnStart est un événement qui se déclenche lorsque la requête démarre.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnStart ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnPreviewContentRequestAsString est un événement qui se déclenche lorsque la demande est prête et qu'elle n'est pas encore envoyée.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnPreviewContentRequestAsString ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnPreviewContentResponseAsString est un événement qui se déclenche lorsque la réponse est reçue et qu'elle n'est pas encore désérialisée.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnPreviewContentResponseAsString ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnPreResult se produit lorsque la demande est terminée mais n'est pas encore terminée. Lorsque OnPreResult est déclenché, nous pouvons faire quelque chose, par exemple obtenir et utiliser le résultat de la requête.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnPreCompleted ( ( r ) => {
DoSomethings ( r . Result ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnException se produit lorsque la demande déclenche une exception.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnException ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
OnCompleted se produit lorsque la demande est terminée.
var result = Rest . Build ( )
. Url ( "[URL]" )
. Command ( "/action" )
. OnCompleted ( ( e ) => {
DoSomethings ( e ) ;
} )
. Payload ( new BigObject { } )
. Post < ResponseObject > ( ) ;
RestClient permet de créer une couche réseau flexible et robuste et il est très simple à utiliser. Ci-dessous vous trouverez une démonstration complète du code et un exemple de code complet.
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 > ( ) ;
}