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

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>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/RESTfulClient/Index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>