.NET API Layer for Freshservice
up vote
0
down vote
favorite
Below is an class to act as API Layer for the Freshservice APIs.
Here's their docs:
https://api.freshservice.com/
Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?
Some of the objects used are "HelpdeskTicket", "Note", "Agent",
Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?
Public Class FreshserviceAPI
Implements IFreshserviceAPI
Public Sub New(portalURL As String, username As String, password As String)
Me.PortalURL = portalURL
Me.UserName = username
Me.Password = password
End Sub
Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
Public Property Password As String = "" Implements IFreshserviceAPI.Password
Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket
Dim ticket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Get,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password)
If response IsNot Nothing Then
ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
Return root.helpdesk_ticket
End Function)
End If
Return ticket
End Function
Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket
Dim createdTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
Return root.item.helpdesk_ticket
End Function)
End If
Return createdTicket
End Function
Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket
Dim updatedTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Put,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
Return root.ticket
End Function)
End If
Return updatedTicket
End Function
Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote
Throw New NotImplementedException()
End Function
Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote
Dim createdNote As Note = Nothing
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=note.ToPostJson())
If response IsNot Nothing Then
createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
Return root.note
End Function)
End If
Return createdNote
End Function
Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment
Dim createdAttachment As Attachment = Nothing
Dim responseJson As String = ""
Using client = New HttpClient()
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
Using formData = New MultipartFormDataContent()
formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")
formData.Add(New ByteArrayContent(attachment.file_data),
name:="helpdesk_note[attachments][resource]",
fileName:=attachment.content_file_name)
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
HttpUtil.SetSslProtocal()
Dim response = client.PostAsync(noteResourceURL, formData).Result
If response.IsSuccessStatusCode Then
Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
responseJson = streamReader.ReadToEnd()
End Using
End If
End Using
End Using
If Not String.IsNullOrWhiteSpace(responseJson) Then
Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
If noteRoot IsNot Nothing Then
Dim createdNote As Note = noteRoot.note
If createdNote IsNot Nothing Then
If createdNote.attachments?.Any() Then
attachment = createdNote.attachments.First()
End If
End If
End If
End If
Return attachment
End Function
Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser
Dim user As User = Nothing
If String.IsNullOrWhiteSpace(emailAddress) Then
'//Fresh will pull ALL agents if you pass a blank email address
'//we don't want that.
Return Nothing
End If
Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
method:=HttpMethod.Get)
If response IsNot Nothing Then
user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
If agentItems?.Any() Then
Dim agent = agentItems.First()
If agent IsNot Nothing Then
Return If(agent Is Nothing, Nothing, agent.agent.user)
End If
End If
Return Nothing
End Function)
End If
Return user
End Function
Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType
Dim item As ItemType = Nothing
Dim responseBodyJSON As String = ""
Using streamReader As New StreamReader(response.GetResponseStream())
responseBodyJSON = streamReader.ReadToEnd()
Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
item = itemExtractor(jsonRoot)
End Using
Return item
End Function
Here's the source of "HelpdeskTicket.vb"
Public Class HelpdeskTicket
<JsonProperty("email")>
Public Property RequesterEmail As String
Public Property category As Object
Public Property cc_email As CcEmail
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property created_at As DateTime?
Public Property deleted As Boolean?
Public Property department_id_value As Object
Public Property display_id As Integer?
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property due_by As DateTime?
Public Property email_config_id As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property frDueBy As DateTime?
Public Property fr_escalated As Boolean?
Public Property group_id As Object
Public Property id As Long?
Public Property impact As Integer?
Public Property isescalated As Boolean?
Public Property item_category As Object
Public Property notes As List(Of NoteResponseRoot)
Public Property owner_id As Object
Public Property priority As Integer?
Public Property requester_id As Long?
Public Property responder_id As Object
Public Property source As Integer?
Public Property spam As Boolean?
Public Property status As Integer?
Public Property sub_category As Object
Public Property subject As String
Public Property ticket_type As String
Public Property to_email As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property updated_at As DateTime?
Public Property urgency As Integer?
Public Property description As String
Public Property description_html As String
Public Property status_name As String
Public Property requester_status_name As String
Public Property priority_name As String
Public Property source_name As String
Public Property requester_name As String
Public Property responder_name As String
Public Property to_emails As Object
Public Property department_name As Object
Public Property assoc_problem_id As Object
Public Property assoc_change_id As Object
Public Property assoc_change_cause_id As Object
Public Property assoc_asset_id As Object
Public Property urgency_name As String
Public Property impact_name As String
Public Property attachments As List(Of Object)
Public Property custom_field As Dictionary(Of String, Object)
Public Property tags As List(Of Object)
End Class
Public Class CcEmail
Public Property cc_emails As List(Of String)
Public Property fwd_emails As List(Of Object)
Public Property reply_cc As List(Of String)
Public Property tkt_cc As List(Of String)
End Class
Public Class TicketResponseRoot
Public Property helpdesk_ticket As HelpdeskTicket
End Class
Public Class TicketPostResponseRoot
Public Property redirect As Object
Public Property item As TicketResponseRoot
End Class
Public Class TicketPutttResponseRoot
Public Property ticket As HelpdeskTicket
End Class
HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:
Imports System.IO
Imports System.Net
Imports System.Net.Http
Imports System.Security.Authentication
Imports System.Text
Namespace HttpUtils
Public Class HttpUtil
Public Shared Function SubmitHttpRequest(resourceURL As String,
method As HttpMethod,
basicAuthUser As String,
basicAuthPassword As String,
Optional requestBodyContent As String = Nothing) As HttpWebResponse
Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
httpWebrequest.Method = method.Method
httpWebrequest.Accept = "application/json"
httpWebrequest.ContentType = "application/json"
httpWebrequest.Timeout = 25000
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)
If requestBodyContent IsNot Nothing Then
Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
writer.Write(requestBodyContent)
End Using
End If
Dim httpResponse As HttpWebResponse = Nothing
Try
SetSslProtocal()
httpResponse = httpWebrequest.GetResponse()
Catch WebEx As WebException
Throw New HttpApiException(requestBody:=requestBodyContent,
message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
innerException:=WebEx)
End Try
Return httpResponse
End Function
''' <summary>
''' Sets the Security Protocal to avoid error:
''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
''' (Authentication failed because remote party has closed the transport stream)
''' See: https://stackoverflow.com/a/47517067/614263
''' </summary>
Public Shared Sub SetSslProtocal()
Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
SecurityProtocolType)
ServicePointManager.SecurityProtocol = Tls12
End Sub
End Class
End Namespace
api vb.net rest client
add a comment |
up vote
0
down vote
favorite
Below is an class to act as API Layer for the Freshservice APIs.
Here's their docs:
https://api.freshservice.com/
Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?
Some of the objects used are "HelpdeskTicket", "Note", "Agent",
Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?
Public Class FreshserviceAPI
Implements IFreshserviceAPI
Public Sub New(portalURL As String, username As String, password As String)
Me.PortalURL = portalURL
Me.UserName = username
Me.Password = password
End Sub
Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
Public Property Password As String = "" Implements IFreshserviceAPI.Password
Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket
Dim ticket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Get,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password)
If response IsNot Nothing Then
ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
Return root.helpdesk_ticket
End Function)
End If
Return ticket
End Function
Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket
Dim createdTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
Return root.item.helpdesk_ticket
End Function)
End If
Return createdTicket
End Function
Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket
Dim updatedTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Put,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
Return root.ticket
End Function)
End If
Return updatedTicket
End Function
Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote
Throw New NotImplementedException()
End Function
Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote
Dim createdNote As Note = Nothing
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=note.ToPostJson())
If response IsNot Nothing Then
createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
Return root.note
End Function)
End If
Return createdNote
End Function
Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment
Dim createdAttachment As Attachment = Nothing
Dim responseJson As String = ""
Using client = New HttpClient()
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
Using formData = New MultipartFormDataContent()
formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")
formData.Add(New ByteArrayContent(attachment.file_data),
name:="helpdesk_note[attachments][resource]",
fileName:=attachment.content_file_name)
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
HttpUtil.SetSslProtocal()
Dim response = client.PostAsync(noteResourceURL, formData).Result
If response.IsSuccessStatusCode Then
Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
responseJson = streamReader.ReadToEnd()
End Using
End If
End Using
End Using
If Not String.IsNullOrWhiteSpace(responseJson) Then
Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
If noteRoot IsNot Nothing Then
Dim createdNote As Note = noteRoot.note
If createdNote IsNot Nothing Then
If createdNote.attachments?.Any() Then
attachment = createdNote.attachments.First()
End If
End If
End If
End If
Return attachment
End Function
Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser
Dim user As User = Nothing
If String.IsNullOrWhiteSpace(emailAddress) Then
'//Fresh will pull ALL agents if you pass a blank email address
'//we don't want that.
Return Nothing
End If
Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
method:=HttpMethod.Get)
If response IsNot Nothing Then
user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
If agentItems?.Any() Then
Dim agent = agentItems.First()
If agent IsNot Nothing Then
Return If(agent Is Nothing, Nothing, agent.agent.user)
End If
End If
Return Nothing
End Function)
End If
Return user
End Function
Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType
Dim item As ItemType = Nothing
Dim responseBodyJSON As String = ""
Using streamReader As New StreamReader(response.GetResponseStream())
responseBodyJSON = streamReader.ReadToEnd()
Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
item = itemExtractor(jsonRoot)
End Using
Return item
End Function
Here's the source of "HelpdeskTicket.vb"
Public Class HelpdeskTicket
<JsonProperty("email")>
Public Property RequesterEmail As String
Public Property category As Object
Public Property cc_email As CcEmail
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property created_at As DateTime?
Public Property deleted As Boolean?
Public Property department_id_value As Object
Public Property display_id As Integer?
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property due_by As DateTime?
Public Property email_config_id As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property frDueBy As DateTime?
Public Property fr_escalated As Boolean?
Public Property group_id As Object
Public Property id As Long?
Public Property impact As Integer?
Public Property isescalated As Boolean?
Public Property item_category As Object
Public Property notes As List(Of NoteResponseRoot)
Public Property owner_id As Object
Public Property priority As Integer?
Public Property requester_id As Long?
Public Property responder_id As Object
Public Property source As Integer?
Public Property spam As Boolean?
Public Property status As Integer?
Public Property sub_category As Object
Public Property subject As String
Public Property ticket_type As String
Public Property to_email As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property updated_at As DateTime?
Public Property urgency As Integer?
Public Property description As String
Public Property description_html As String
Public Property status_name As String
Public Property requester_status_name As String
Public Property priority_name As String
Public Property source_name As String
Public Property requester_name As String
Public Property responder_name As String
Public Property to_emails As Object
Public Property department_name As Object
Public Property assoc_problem_id As Object
Public Property assoc_change_id As Object
Public Property assoc_change_cause_id As Object
Public Property assoc_asset_id As Object
Public Property urgency_name As String
Public Property impact_name As String
Public Property attachments As List(Of Object)
Public Property custom_field As Dictionary(Of String, Object)
Public Property tags As List(Of Object)
End Class
Public Class CcEmail
Public Property cc_emails As List(Of String)
Public Property fwd_emails As List(Of Object)
Public Property reply_cc As List(Of String)
Public Property tkt_cc As List(Of String)
End Class
Public Class TicketResponseRoot
Public Property helpdesk_ticket As HelpdeskTicket
End Class
Public Class TicketPostResponseRoot
Public Property redirect As Object
Public Property item As TicketResponseRoot
End Class
Public Class TicketPutttResponseRoot
Public Property ticket As HelpdeskTicket
End Class
HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:
Imports System.IO
Imports System.Net
Imports System.Net.Http
Imports System.Security.Authentication
Imports System.Text
Namespace HttpUtils
Public Class HttpUtil
Public Shared Function SubmitHttpRequest(resourceURL As String,
method As HttpMethod,
basicAuthUser As String,
basicAuthPassword As String,
Optional requestBodyContent As String = Nothing) As HttpWebResponse
Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
httpWebrequest.Method = method.Method
httpWebrequest.Accept = "application/json"
httpWebrequest.ContentType = "application/json"
httpWebrequest.Timeout = 25000
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)
If requestBodyContent IsNot Nothing Then
Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
writer.Write(requestBodyContent)
End Using
End If
Dim httpResponse As HttpWebResponse = Nothing
Try
SetSslProtocal()
httpResponse = httpWebrequest.GetResponse()
Catch WebEx As WebException
Throw New HttpApiException(requestBody:=requestBodyContent,
message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
innerException:=WebEx)
End Try
Return httpResponse
End Function
''' <summary>
''' Sets the Security Protocal to avoid error:
''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
''' (Authentication failed because remote party has closed the transport stream)
''' See: https://stackoverflow.com/a/47517067/614263
''' </summary>
Public Shared Sub SetSslProtocal()
Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
SecurityProtocolType)
ServicePointManager.SecurityProtocol = Tls12
End Sub
End Class
End Namespace
api vb.net rest client
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
Below is an class to act as API Layer for the Freshservice APIs.
Here's their docs:
https://api.freshservice.com/
Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?
Some of the objects used are "HelpdeskTicket", "Note", "Agent",
Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?
Public Class FreshserviceAPI
Implements IFreshserviceAPI
Public Sub New(portalURL As String, username As String, password As String)
Me.PortalURL = portalURL
Me.UserName = username
Me.Password = password
End Sub
Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
Public Property Password As String = "" Implements IFreshserviceAPI.Password
Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket
Dim ticket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Get,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password)
If response IsNot Nothing Then
ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
Return root.helpdesk_ticket
End Function)
End If
Return ticket
End Function
Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket
Dim createdTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
Return root.item.helpdesk_ticket
End Function)
End If
Return createdTicket
End Function
Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket
Dim updatedTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Put,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
Return root.ticket
End Function)
End If
Return updatedTicket
End Function
Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote
Throw New NotImplementedException()
End Function
Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote
Dim createdNote As Note = Nothing
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=note.ToPostJson())
If response IsNot Nothing Then
createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
Return root.note
End Function)
End If
Return createdNote
End Function
Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment
Dim createdAttachment As Attachment = Nothing
Dim responseJson As String = ""
Using client = New HttpClient()
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
Using formData = New MultipartFormDataContent()
formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")
formData.Add(New ByteArrayContent(attachment.file_data),
name:="helpdesk_note[attachments][resource]",
fileName:=attachment.content_file_name)
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
HttpUtil.SetSslProtocal()
Dim response = client.PostAsync(noteResourceURL, formData).Result
If response.IsSuccessStatusCode Then
Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
responseJson = streamReader.ReadToEnd()
End Using
End If
End Using
End Using
If Not String.IsNullOrWhiteSpace(responseJson) Then
Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
If noteRoot IsNot Nothing Then
Dim createdNote As Note = noteRoot.note
If createdNote IsNot Nothing Then
If createdNote.attachments?.Any() Then
attachment = createdNote.attachments.First()
End If
End If
End If
End If
Return attachment
End Function
Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser
Dim user As User = Nothing
If String.IsNullOrWhiteSpace(emailAddress) Then
'//Fresh will pull ALL agents if you pass a blank email address
'//we don't want that.
Return Nothing
End If
Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
method:=HttpMethod.Get)
If response IsNot Nothing Then
user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
If agentItems?.Any() Then
Dim agent = agentItems.First()
If agent IsNot Nothing Then
Return If(agent Is Nothing, Nothing, agent.agent.user)
End If
End If
Return Nothing
End Function)
End If
Return user
End Function
Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType
Dim item As ItemType = Nothing
Dim responseBodyJSON As String = ""
Using streamReader As New StreamReader(response.GetResponseStream())
responseBodyJSON = streamReader.ReadToEnd()
Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
item = itemExtractor(jsonRoot)
End Using
Return item
End Function
Here's the source of "HelpdeskTicket.vb"
Public Class HelpdeskTicket
<JsonProperty("email")>
Public Property RequesterEmail As String
Public Property category As Object
Public Property cc_email As CcEmail
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property created_at As DateTime?
Public Property deleted As Boolean?
Public Property department_id_value As Object
Public Property display_id As Integer?
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property due_by As DateTime?
Public Property email_config_id As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property frDueBy As DateTime?
Public Property fr_escalated As Boolean?
Public Property group_id As Object
Public Property id As Long?
Public Property impact As Integer?
Public Property isescalated As Boolean?
Public Property item_category As Object
Public Property notes As List(Of NoteResponseRoot)
Public Property owner_id As Object
Public Property priority As Integer?
Public Property requester_id As Long?
Public Property responder_id As Object
Public Property source As Integer?
Public Property spam As Boolean?
Public Property status As Integer?
Public Property sub_category As Object
Public Property subject As String
Public Property ticket_type As String
Public Property to_email As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property updated_at As DateTime?
Public Property urgency As Integer?
Public Property description As String
Public Property description_html As String
Public Property status_name As String
Public Property requester_status_name As String
Public Property priority_name As String
Public Property source_name As String
Public Property requester_name As String
Public Property responder_name As String
Public Property to_emails As Object
Public Property department_name As Object
Public Property assoc_problem_id As Object
Public Property assoc_change_id As Object
Public Property assoc_change_cause_id As Object
Public Property assoc_asset_id As Object
Public Property urgency_name As String
Public Property impact_name As String
Public Property attachments As List(Of Object)
Public Property custom_field As Dictionary(Of String, Object)
Public Property tags As List(Of Object)
End Class
Public Class CcEmail
Public Property cc_emails As List(Of String)
Public Property fwd_emails As List(Of Object)
Public Property reply_cc As List(Of String)
Public Property tkt_cc As List(Of String)
End Class
Public Class TicketResponseRoot
Public Property helpdesk_ticket As HelpdeskTicket
End Class
Public Class TicketPostResponseRoot
Public Property redirect As Object
Public Property item As TicketResponseRoot
End Class
Public Class TicketPutttResponseRoot
Public Property ticket As HelpdeskTicket
End Class
HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:
Imports System.IO
Imports System.Net
Imports System.Net.Http
Imports System.Security.Authentication
Imports System.Text
Namespace HttpUtils
Public Class HttpUtil
Public Shared Function SubmitHttpRequest(resourceURL As String,
method As HttpMethod,
basicAuthUser As String,
basicAuthPassword As String,
Optional requestBodyContent As String = Nothing) As HttpWebResponse
Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
httpWebrequest.Method = method.Method
httpWebrequest.Accept = "application/json"
httpWebrequest.ContentType = "application/json"
httpWebrequest.Timeout = 25000
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)
If requestBodyContent IsNot Nothing Then
Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
writer.Write(requestBodyContent)
End Using
End If
Dim httpResponse As HttpWebResponse = Nothing
Try
SetSslProtocal()
httpResponse = httpWebrequest.GetResponse()
Catch WebEx As WebException
Throw New HttpApiException(requestBody:=requestBodyContent,
message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
innerException:=WebEx)
End Try
Return httpResponse
End Function
''' <summary>
''' Sets the Security Protocal to avoid error:
''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
''' (Authentication failed because remote party has closed the transport stream)
''' See: https://stackoverflow.com/a/47517067/614263
''' </summary>
Public Shared Sub SetSslProtocal()
Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
SecurityProtocolType)
ServicePointManager.SecurityProtocol = Tls12
End Sub
End Class
End Namespace
api vb.net rest client
Below is an class to act as API Layer for the Freshservice APIs.
Here's their docs:
https://api.freshservice.com/
Aside from some much needed comments, what issues do you see with the implementation? I know it could probably use more comments throughout, but what else do you see?
Some of the objects used are "HelpdeskTicket", "Note", "Agent",
Each of those have accompaning "Root" objects which are tailored to the Json based on how the "HelpdeskTicket" for instance is housed in the Response to a GET, PUT, or POST Request. Source of "HelpdeskTicket" is provided at the bottom to help demonstrate that. I'm a little bit new to using JSON.NET (newtonsoft) so would appreciate some feedback on that style of creating "Root" objects like that -- is that the right way to go? What's the best way to deal with the different types of Json responses, each having in how they house the main entity data you are trying to get to?
Public Class FreshserviceAPI
Implements IFreshserviceAPI
Public Sub New(portalURL As String, username As String, password As String)
Me.PortalURL = portalURL
Me.UserName = username
Me.Password = password
End Sub
Public Property PortalURL As String = "" Implements IFreshserviceAPI.PortalURL
Public Property UserName As String = "" Implements IFreshserviceAPI.UserName
Public Property Password As String = "" Implements IFreshserviceAPI.Password
Public Function GetTicket(id As Long) As HelpdeskTicket Implements IFreshserviceAPI.GetTicket
Dim ticket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Get,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password)
If response IsNot Nothing Then
ticket = GetItemFromResponse(response, Function(root As TicketResponseRoot)
Return root.helpdesk_ticket
End Function)
End If
Return ticket
End Function
Public Function CreateTicket(ticket As HelpdeskTicket) As HelpdeskTicket Implements IFreshserviceAPI.CreateTicket
Dim createdTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
createdTicket = GetItemFromResponse(response, Function(root As TicketPostResponseRoot)
Return root.item.helpdesk_ticket
End Function)
End If
Return createdTicket
End Function
Public Function UpdateTicket(ticket As HelpdeskTicket, id As Long) As HelpdeskTicket Implements IFreshserviceAPI.UpdateTicket
Dim updatedTicket As HelpdeskTicket = Nothing
Dim ticketResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{id}.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(ticketResourceURL,
method:=HttpMethod.Put,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=ticket.ToPostJson)
If response IsNot Nothing Then
updatedTicket = GetItemFromResponse(response, Function(root As TicketPutttResponseRoot)
Return root.ticket
End Function)
End If
Return updatedTicket
End Function
Public Function GetNote(id As Long) As Note Implements IFreshserviceAPI.GetNote
Throw New NotImplementedException()
End Function
Public Function CreateNote(note As Note, ticketID As Long) As Note Implements IFreshserviceAPI.CreateNote
Dim createdNote As Note = Nothing
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(noteResourceURL,
method:=HttpMethod.Post,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
requestBodyContent:=note.ToPostJson())
If response IsNot Nothing Then
createdNote = GetItemFromResponse(response, Function(root As NoteResponseRoot)
Return root.note
End Function)
End If
Return createdNote
End Function
Public Function CreateNoteWithAttachment(noteBody As String, attachment As Attachment, ticketID As Long) As Attachment Implements IFreshserviceAPI.CreateNoteWithAttachment
Dim createdAttachment As Attachment = Nothing
Dim responseJson As String = ""
Using client = New HttpClient()
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserName & ":" & Password))
client.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Basic", basicAuthCreds)
Using formData = New MultipartFormDataContent()
formData.Add(New StringContent(noteBody), name:="helpdesk_note[body]")
formData.Add(New ByteArrayContent(attachment.file_data),
name:="helpdesk_note[attachments][resource]",
fileName:=attachment.content_file_name)
Dim noteResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/helpdesk/tickets/{ticketID}/conversations/note.json"
HttpUtil.SetSslProtocal()
Dim response = client.PostAsync(noteResourceURL, formData).Result
If response.IsSuccessStatusCode Then
Using streamReader As New StreamReader(response.Content.ReadAsStreamAsync().Result)
responseJson = streamReader.ReadToEnd()
End Using
End If
End Using
End Using
If Not String.IsNullOrWhiteSpace(responseJson) Then
Dim noteRoot = JsonConvert.DeserializeObject(Of NoteResponseRoot)(responseJson)
If noteRoot IsNot Nothing Then
Dim createdNote As Note = noteRoot.note
If createdNote IsNot Nothing Then
If createdNote.attachments?.Any() Then
attachment = createdNote.attachments.First()
End If
End If
End If
End If
Return attachment
End Function
Public Function FindAgentUser(emailAddress As String) As User Implements IFreshserviceAPI.FindAgentUser
Dim user As User = Nothing
If String.IsNullOrWhiteSpace(emailAddress) Then
'//Fresh will pull ALL agents if you pass a blank email address
'//we don't want that.
Return Nothing
End If
Dim usersResourceURL As String = $"{Me.PortalURL.TrimEnd("/"c)}/agents.json?query={WebUtility.UrlEncode("email is " & emailAddress)}"
Dim response As HttpWebResponse = HttpUtil.SubmitHttpRequest(usersResourceURL,
basicAuthUser:=Me.UserName,
basicAuthPassword:=Me.Password,
method:=HttpMethod.Get)
If response IsNot Nothing Then
user = GetItemFromResponse(response, Function(agentItems As List(Of AgentListItem))
If agentItems?.Any() Then
Dim agent = agentItems.First()
If agent IsNot Nothing Then
Return If(agent Is Nothing, Nothing, agent.agent.user)
End If
End If
Return Nothing
End Function)
End If
Return user
End Function
Private Function GetItemFromResponse(Of ItemType, ItemRootType)(response As HttpWebResponse,
itemExtractor As Func(Of ItemRootType, ItemType)) As ItemType
Dim item As ItemType = Nothing
Dim responseBodyJSON As String = ""
Using streamReader As New StreamReader(response.GetResponseStream())
responseBodyJSON = streamReader.ReadToEnd()
Dim jsonRoot As ItemRootType = JsonConvert.DeserializeObject(Of ItemRootType)(responseBodyJSON)
item = itemExtractor(jsonRoot)
End Using
Return item
End Function
Here's the source of "HelpdeskTicket.vb"
Public Class HelpdeskTicket
<JsonProperty("email")>
Public Property RequesterEmail As String
Public Property category As Object
Public Property cc_email As CcEmail
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property created_at As DateTime?
Public Property deleted As Boolean?
Public Property department_id_value As Object
Public Property display_id As Integer?
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property due_by As DateTime?
Public Property email_config_id As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property frDueBy As DateTime?
Public Property fr_escalated As Boolean?
Public Property group_id As Object
Public Property id As Long?
Public Property impact As Integer?
Public Property isescalated As Boolean?
Public Property item_category As Object
Public Property notes As List(Of NoteResponseRoot)
Public Property owner_id As Object
Public Property priority As Integer?
Public Property requester_id As Long?
Public Property responder_id As Object
Public Property source As Integer?
Public Property spam As Boolean?
Public Property status As Integer?
Public Property sub_category As Object
Public Property subject As String
Public Property ticket_type As String
Public Property to_email As Object
<JsonConverter(GetType(IsoDateTimeConverter))>
Public Property updated_at As DateTime?
Public Property urgency As Integer?
Public Property description As String
Public Property description_html As String
Public Property status_name As String
Public Property requester_status_name As String
Public Property priority_name As String
Public Property source_name As String
Public Property requester_name As String
Public Property responder_name As String
Public Property to_emails As Object
Public Property department_name As Object
Public Property assoc_problem_id As Object
Public Property assoc_change_id As Object
Public Property assoc_change_cause_id As Object
Public Property assoc_asset_id As Object
Public Property urgency_name As String
Public Property impact_name As String
Public Property attachments As List(Of Object)
Public Property custom_field As Dictionary(Of String, Object)
Public Property tags As List(Of Object)
End Class
Public Class CcEmail
Public Property cc_emails As List(Of String)
Public Property fwd_emails As List(Of Object)
Public Property reply_cc As List(Of String)
Public Property tkt_cc As List(Of String)
End Class
Public Class TicketResponseRoot
Public Property helpdesk_ticket As HelpdeskTicket
End Class
Public Class TicketPostResponseRoot
Public Property redirect As Object
Public Property item As TicketResponseRoot
End Class
Public Class TicketPutttResponseRoot
Public Property ticket As HelpdeskTicket
End Class
HttpUtil is a utility class used to submit HTTP requests. Please not the use of HttpApiException. That's a custom exception that was created to give us the capability to capture the request that was used in the event of an HTTP error (in addition to the response), so that we can log the request body elsewhere in the application upon API errors. Here's HttpUtil:
Imports System.IO
Imports System.Net
Imports System.Net.Http
Imports System.Security.Authentication
Imports System.Text
Namespace HttpUtils
Public Class HttpUtil
Public Shared Function SubmitHttpRequest(resourceURL As String,
method As HttpMethod,
basicAuthUser As String,
basicAuthPassword As String,
Optional requestBodyContent As String = Nothing) As HttpWebResponse
Dim httpWebrequest As HttpWebRequest = WebRequest.Create(resourceURL)
httpWebrequest.Method = method.Method
httpWebrequest.Accept = "application/json"
httpWebrequest.ContentType = "application/json"
httpWebrequest.Timeout = 25000
Dim basicAuthCreds As String = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(basicAuthUser & ":" & basicAuthPassword))
httpWebrequest.Headers.Add("Authorization", "Basic " + basicAuthCreds)
If requestBodyContent IsNot Nothing Then
Using writer As New StreamWriter(httpWebrequest.GetRequestStream())
writer.Write(requestBodyContent)
End Using
End If
Dim httpResponse As HttpWebResponse = Nothing
Try
SetSslProtocal()
httpResponse = httpWebrequest.GetResponse()
Catch WebEx As WebException
Throw New HttpApiException(requestBody:=requestBodyContent,
message:=$"HttpUtil.SubmitHttpRequest -- HTTP Error occurred at {DateTime.Now.ToString()}, see inner exception for details",
innerException:=WebEx)
End Try
Return httpResponse
End Function
''' <summary>
''' Sets the Security Protocal to avoid error:
''' "Additional information: The underlying connection was closed: An unexpected error occurred on a send.
''' (Authentication failed because remote party has closed the transport stream)
''' See: https://stackoverflow.com/a/47517067/614263
''' </summary>
Public Shared Sub SetSslProtocal()
Const _Tls12 As SslProtocols = DirectCast(&HC00, SslProtocols)
Const Tls12 As SecurityProtocolType = DirectCast(_Tls12,
SecurityProtocolType)
ServicePointManager.SecurityProtocol = Tls12
End Sub
End Class
End Namespace
api vb.net rest client
api vb.net rest client
edited 13 mins ago
Heslacher
44.8k460155
44.8k460155
asked Apr 6 at 15:39
unnknown
15316
15316
add a comment |
add a comment |
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191418%2fnet-api-layer-for-freshservice%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191418%2fnet-api-layer-for-freshservice%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown