(MVC) MVC (2019)

Simplest VB.NET WebApi2 client for RESTful microServices documented by Swagger/OpenAPI.

1. What is Swagger API

Too many fashion word is appearing in IT in couple last years. But it means some simple principles what existing in our world during many-many years. One of stupid word (looks as new) is webServices and microDervices. And to emphasize stupidity this worlds need to write in lowerCamelCase instead UpperCamelCase. Stupid young programmer don't understand than microServices and webServices has written by any VB.NET programmers every days since 2002 year. I wrote article (for example) about this two word - How classic ASP.NET programmers has realized WEB.API since 2005 year. And similar means carry any another fashion word in IT, for example during more then 10 years all VB WEB programmers has been write various Web Services, for example this is second reincarnation WebServices Типовий SOAP/WSDL сервіс.. This services has been documented by DISCO-file. Modern analogue of DISCO-file is Swagger-type of documentation WebServices.

So Swagger UI is JavaScript/CSS UI intended to documentation of RESTful API, its contains some parts (services and definition of structure used by service) and look as below. Commented version is an my ancient historical version this same API with JavaScriptSerializer.



And code below is no more then modern reincarnation of stupid, advertised and not workable WCF Client. Any self-respecting programmer has own implementation of this simplest idea - this is my own first synchronous version as replacement WCF Client - WCF_CLIENT - клиент Web-сервиса, WCF_CLIENT - клиент Web-сервиса and this is part of my asynchronous library - Multithreading Parsers with Parallel, CsQuery, Newtonsoft.Json, OfficeOpenXml and IAsyncResult/AsyncCallback.

2. Base class - my WebApi2 client of JSON Web Token (JWT) microServices.

Below I publish synchronous part of my WebApi2 client of JSON Web Token (JWT) microServices.


   1:  Imports System.Net
   2:  Imports System.Net.Http
   3:  Imports System.Net.Http.Headers
   4:  Imports System.Runtime.CompilerServices
   5:  Imports System.Text
   6:  Imports System.Web.Script.Serialization
   7:  Imports Newtonsoft.Json
   8:  Imports Newtonsoft.Json.Converters
   9:  Imports Newtonsoft.Json.Linq
  10:   
  11:  Public Class WebApi2Result
  12:      Property IsSuccess As Boolean
  13:      Property Result As String
  14:      Property Headers As HttpResponseHeaders
  15:      Property Status As HttpStatusCode
  16:      Public Sub New(Response As HttpResponseMessage)
  17:          Result = Response.Content.ReadAsStringAsync().Result 'sync, Await without .Result
  18:          Headers = Response.Headers
  19:          Status = Response.StatusCode
  20:          If Response.IsSuccessStatusCode Then
  21:              IsSuccess = True
  22:          Else
  23:              IsSuccess = False
  24:          End If
  25:      End Sub
  26:   
  27:      Public Function HeaderToString() As String
  28:          Dim Str1 As New StringBuilder
  29:          If Headers IsNot Nothing Then
  30:              For Each One In Headers
  31:                  Str1.AppendLine()
  32:                  Str1.Append(One.Key & " : ")
  33:                  For Each Val As String In One.Value
  34:                      Str1.Append(Val & ",")
  35:                  Next
  36:                  Str1.Length = Str1.Length - 1
  37:              Next
  38:              Return Str1.ToString
  39:          Else
  40:              Return ""
  41:          End If
  42:   
  43:      End Function
  44:   
  45:  End Class
  46:   
  47:  Public Class WebApi2
  48:   
  49:      Dim BaseApiURL As String
  50:      Dim Client As HttpClient
  53:   
  54:      Public Sub New()
  55:          BaseApiURL = My.Settings.BaseApiURL
  56:          Client = New HttpClient()
  57:          Client.BaseAddress = New Uri(BaseApiURL)
  58:          Client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
  59:          'Serializer = New JavaScriptSerializer()
  60:      End Sub
  61:   
  62:      Public Sub New(BaseURL As String)
  63:          BaseApiURL = BaseURL
  64:          Client = New HttpClient()
  65:          Client.BaseAddress = New Uri(BaseApiURL)
  66:          Client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
  67:      End Sub
  68:   
  69:      Function Err1(Ex As Exception, Response As HttpResponseMessage) As WebApi2Result
  70:          Dim Ret1 As New WebApi2Result(New HttpResponseMessage(HttpStatusCode.SeeOther))
  71:          Ret1.IsSuccess = False
  72:          Ret1.Status = Response.StatusCode
  73:          Ret1.Headers = Response.Headers
  74:          Ret1.Result = Ex.Message
  75:          If Ex.InnerException IsNot Nothing Then
  76:              Ret1.Result = Ex.Message & vbCrLf & Ex.InnerException.ToString
  77:          End If
  78:          Return Ret1
  79:      End Function
  80:   
  81:      Public Function GetWithoutAU(ApiPoint As String) As WebApi2Result
  82:          Dim Response As HttpResponseMessage
  83:          Try
  84:              Response = Client.GetAsync(ApiPoint).Result           'sync, Await without .Result
  85:              Return New WebApi2Result(Response)
  86:          Catch ex As Exception
  87:              Return Err1(ex, Response)
  88:          End Try
  89:      End Function
  90:   
  91:      Public Function Post(ApiPoint As String, InputJsonObject As Object) As WebApi2Result
  92:          Dim Response As HttpResponseMessage
  93:          Try
  94:              'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
  95:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
  96:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
  97:              Response = Client.PostAsync(ApiPoint, Content).Result 'sync, Await without .Result
  98:              Return New WebApi2Result(Response)
  99:          Catch ex As Exception
 100:              Return Err1(ex, Response)
 101:          End Try
 102:      End Function
 103:   
 104:      Public Function GetWithBearerHeader(ApiPoint As String, BearerToken As String) As WebApi2Result
 105:          Dim Response As HttpResponseMessage
 106:          Try
 107:              Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
 108:              Response = Client.GetAsync(ApiPoint).Result           'sync, Await without .Result
 109:              Return New WebApi2Result(Response)
 110:          Catch ex As Exception
 111:              Return Err1(ex, Response)
 112:          End Try
 113:      End Function
 114:   
 115:      Public Function PostWithBearerHeader(ApiPoint As String, BearerToken As String) As WebApi2Result
 116:          Dim Response As HttpResponseMessage
 117:          Try
 118:              Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
 119:              Response = Client.PostAsync(ApiPoint, New StringContent("")).Result 'sync, Await without .Result
 120:              Return New WebApi2Result(Response)
 121:          Catch ex As Exception
 122:              Return Err1(ex, Response)
 123:          End Try
 124:      End Function
 125:   
 126:      Public Function PostWithBearerHeader(ApiPoint As String, BearerToken As String, InputJsonObject As Object) As WebApi2Result
 127:          Dim Response As HttpResponseMessage
 128:          Try
 129:              Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
 130:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
 131:              'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
 132:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
 133:              Response = Client.PostAsync(ApiPoint, Content).Result 'sync, Await without .Result
 134:              Return New WebApi2Result(Response)
 135:          Catch ex As Exception
 136:              Return Err1(ex, Response)
 137:          End Try
 138:      End Function
 139:   
 140:      Public Function PutWithBearerHeader(ApiPoint As String, BearerToken As String, InputJsonObject As Object) As WebApi2Result
 141:          Dim Response As HttpResponseMessage
 142:          Try
 143:              Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
 144:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
 145:              'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
 146:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
 147:              Response = Client.PutAsync(ApiPoint, Content).Result 'sync, Await without .Result
 148:              Return New WebApi2Result(Response)
 149:          Catch ex As Exception
 150:              Return Err1(ex, Response)
 151:          End Try
 152:      End Function
 153:   
 154:      Public Function DeleteWithBearerHeader(ApiPoint As String, BearerToken As String, InputJsonObject As Object) As WebApi2Result
 155:          Dim Response As HttpResponseMessage
 156:          Try
 157:              Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", BearerToken)
 158:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
 159:              'Dim JsonString As String = Serializer.Serialize(InputJsonObject)
 160:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
 161:              Response = Client.SendAsync(New HttpRequestMessage(HttpMethod.Delete, ApiPoint) With {.Content = Content}).Result
 162:              Return New WebApi2Result(Response)
 163:          Catch ex As Exception
 164:              Return Err1(ex, Response)
 165:          End Try
 166:      End Function
 167:   
 168:      Public Function GetWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String) As WebApi2Result
 169:          Dim Response As HttpResponseMessage
 170:          Try
 171:              Client.DefaultRequestHeaders.Clear()
 172:              Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
 173:              Response = Client.GetAsync(ApiPoint).Result           'sync, Await without .Result
 174:              Return New WebApi2Result(Response)
 175:          Catch ex As Exception
 176:              Return Err1(ex, Response)
 177:          End Try
 178:      End Function
 179:   
 180:      Public Function PutWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String, InputJsonObject As Object) As WebApi2Result
 181:          Dim Response As HttpResponseMessage
 182:          Try
 183:              Client.DefaultRequestHeaders.Clear()
 184:              Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
 185:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
 186:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
 187:              Response = Client.PutAsync(ApiPoint, Content).Result 'sync, Await without .Result
 188:              Return New WebApi2Result(Response)
 189:          Catch ex As Exception
 190:              Return Err1(ex, Response)
 191:          End Try
 192:      End Function
 193:   
 194:      Public Function PostWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String, InputJsonObject As Object) As WebApi2Result
 195:          Dim Response As HttpResponseMessage
 196:          Try
 197:              Client.DefaultRequestHeaders.Clear()
 198:              Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
 199:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
 200:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
 201:              Response = Client.PostAsync(ApiPoint, Content).Result 'sync, Await without .Result
 202:              Return New WebApi2Result(Response)
 203:          Catch ex As Exception
 204:              Return Err1(ex, Response)
 205:          End Try
 206:      End Function
 207:   
 208:      Public Function DeleteWithAPIKeyHeader(ApiPoint As String, XAPIKeyToken As String, InputJsonObject As Object) As WebApi2Result
 209:          Dim Response As HttpResponseMessage
 210:          Try
 211:              Client.DefaultRequestHeaders.Clear()
 212:              Client.DefaultRequestHeaders.Add("X-API-Key", XAPIKeyToken)
 213:              Dim JsonString As String = JsonConvert.SerializeObject(InputJsonObject, DoubleNumericFormaterSerializerSettings)
 214:              Dim Content = New StringContent(JsonString, Encoding.UTF8, "application/json")
 215:              Response = Client.SendAsync(New HttpRequestMessage(HttpMethod.Delete, ApiPoint) With {.Content = Content}).Result
 216:              Return New WebApi2Result(Response)
 217:          Catch ex As Exception
 218:              Return Err1(ex, Response)
 219:          End Try
 220:      End Function
 221:   

3. Extend base class.




This is a way to extend base class by extension function.


   1:  Imports System.Runtime.CompilerServices
   2:  Imports System.Text
   3:  Imports Newtonsoft.Json
   4:  Imports Newtonsoft.Json.Linq
   5:   
   6:  Public Module BinanceAPIExtension
   7:   
   8:      <Extension()>
   9:      Public Function BinanceApiTrades(Binance As WebApi2, Symbol As String, ByRef BinanceTrades As List(Of TradeModel)) As Boolean
  10:          Dim Trades = Binance.GetWithoutAU("/api/v3/trades?symbol=" & Symbol)
  11:          If Trades.IsSuccess Then
  12:              Dim TradesArr1 As JArray = JArray.Parse(Trades.Result)
  13:              BinanceTrades = JsonConvert.DeserializeObject(Of List(Of TradeModel))(TradesArr1.ToString)
  14:              Return True
  15:          Else
  16:              MsgBox(Trades.Result & vbCrLf & Trades.Status.ToString & vbCrLf & FormatObjForPrint(Trades.Result) & vbCrLf & Trades.HeaderToString, MsgBoxStyle.Critical, "/api/v3/trades Error")
  17:              Return False
  18:          End If
  19:      End Function
  20:   
  21:      <Extension()>
  22:      Public Function BinanceApiExchangeInfo(Binance As WebApi2, ByRef BinanceExchangeSymbols As List(Of BinanceExchangeSymbol)) As Boolean
  23:          Dim Info = Binance.GetWithoutAU("/api/v3/exchangeInfo")
  24:          If Info.IsSuccess Then
  25:              Dim TradesArr1 As JArray = JArray.Parse(Info.Result)
  26:              BinanceExchangeSymbols = JsonConvert.DeserializeObject(Of List(Of BinanceExchangeSymbol))(TradesArr1.ToString)
  27:              Return True
  28:          Else
  29:              MsgBox(Info.Result & vbCrLf & Info.Status.ToString & vbCrLf & Info.HeaderToString, MsgBoxStyle.Critical, "/api/v3/exchangeInfo Error")
  30:              Return False
  31:          End If
  32:      End Function
  33:   
  34:   

4. Other way to expand WebApi Client.


This is a simplest WebApi2 client, in reality it can be expanded by many future, for example by various converters Customize Newtonsoft.Json Serializer/Deserializer to convert Javascript Datetime and Number to .NET datatype.


5. What is JWT OpenID authentication and how it working.

But, how to use this API in practice to implement JWT OpenID authentication? Please, look at my code below.


   1:  Imports System.IdentityModel.Tokens.Jwt
   2:  Imports System.Net.Http
   3:  Imports Newtonsoft.Json
   4:  Imports Newtonsoft.Json.Linq
   5:   
   6:  Public Class StartForm
   7:   
   8:      Public WithEvents LoginTimer1 As New Timer
   9:      Dim Folex As WebApi2
  10:      Dim CurrentLoginToken As LoginToken
  ...   
  17:      Private Sub StartForm_Load(sender As Object, e As EventArgs) Handles Me.Load
  18:          Folex = New WebApi2
  19:          Text &= " (" & My.Application.Info.Version.ToString & ")"
  20:          LoginTimer1.Interval = 1000
  21:      End Sub
  22:   
  23:      Private Sub LoginButton1_Click(sender As Object, e As EventArgs) Handles LoginButton1.Click
  24:   
  25:          Dim LoginPhase1 = Folex.Post("/api/auth/login", New With {.login = LoginTextBox1.Text, .password = PassTextBox1.Text, .isAdmin = False})
  26:          If LoginPhase1.IsSuccess Then
  27:   
  28:              Dim ResponseJson As JObject = JObject.Parse(LoginPhase1.Result)
  29:              Dim Token As String = ResponseJson("tempToken").Value(Of String)
  30:              Dim TwoFAuKey As String = InputBox("Get 2FA Key", "Login", "000000")
  31:   
  32:              If TwoFAuKey = "000000" Then
  33:                  Exit Sub
  34:              Else
  35:                  Dim LoginPhase2 = Folex.Post("/api/auth/twoFactorAuthCodeLogin", New With {.code = TwoFAuKey, .tempToken = Token, .isAdmin = False})
  36:                  If LoginPhase2.IsSuccess Then
  37:                      If Not LoginPhase2.Result.Contains("errorMsg") Then
  38:                          CurrentLoginToken = JsonConvert.DeserializeObject(Of LoginToken)(LoginPhase2.Result)
  39:                          AutoClosingMessageBox.Show(FormatLoginToken, "Login success")
  40:                          LoginTokenTextBox.Text = FormatLoginToken()
  41:                          LoginTimer1.Start()
  42:                          KeysButton.Enabled = True
  43:                          BalanceButton.Enabled = True
  44:                          DynamicRateButton.Enabled = True
  45:                      Else
  46:                          MsgBox(LoginPhase2.Result, MsgBoxStyle.Critical, "TwoFAu Error")
  47:                      End If
  48:                  Else
  49:                      MsgBox(LoginPhase2.Result, MsgBoxStyle.Critical, "TwoFAu Error")
  50:                  End If
  51:              End If
  52:          Else
  53:              MsgBox(LoginPhase1.Result, MsgBoxStyle.Critical, "Login Error")
  54:          End If
  55:      End Sub
  56:   
  57:      Private Sub LoginTimer1_Tick(sender As Object, e As EventArgs) Handles LoginTimer1.Tick
  58:          Dim RestTime As Double = (CurrentLoginToken.expire_token - DateTime.UtcNow).TotalSeconds
  59:          If RestTime < 10 Then
  60:              Dim RefreshToken = Folex.PostWithBearerHeader("/api/auth/refresh", CurrentLoginToken.refresh_token)
  61:              If RefreshToken.IsSuccess Then
  62:                  If Not RefreshToken.Result.Contains("errorMsg") Then
  63:                      CurrentLoginToken = JsonConvert.DeserializeObject(Of LoginToken)(RefreshToken.Result)
  64:                      LoginTimer1.Stop()
  65:                      LoginTimer1.Start()
  66:                      AutoClosingMessageBox.Show(FormatLoginToken, "Refresh token success")
  67:                  Else
  68:                      LoginTimer1.Stop()
  69:                      MsgBox(RefreshToken.Result, MsgBoxStyle.Critical, "Refresh token Error")
  70:                  End If
  71:              Else
  72:                  LoginTimer1.Stop()
  73:                  MsgBox(RefreshToken.Result, MsgBoxStyle.Critical, "Refresh token Error")
  74:              End If
  75:          Else
  76:              Me.InvokeOnUiThreadIfRequired(Sub() ToolStripStatusLabel1.Text = "Online " & CInt(RestTime))
  77:              Me.InvokeOnUiThreadIfRequired(Sub() ToolStripContainer1.Refresh())
  78:          End If
  79:   
  80:      End Sub
  ...   
 164:  Public Class LoginToken
 165:      Property login As String
 166:      Property access_token As String
 167:      Property expire_token As DateTime
 168:      Property refresh_token As String
 169:  End Class
 170:   
  ...   

This my program pass Two Form Authentication and show Refresh and Access token.




Exactly in the same way is use any modern JacaScript environment, like Angular, where you can see headers Authorization: Bearer XXXXXXX.XXXX.XXXX




Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19
Link to this page: http://www.vb-net.com/RESTfulClient/Index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <MAIL ME>  <ABOUT ME>  < THANKS ME>