How to use GetStringAsync in VB.NET - json

I don't really know what I'm going. Trying to gather small pieces of code from the web
I ended up with this:
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json.Linq
Module Module1
Sub Main()
LoadData()
End Sub
Private Async Sub LoadData()
Dim client As New Net.Http.HttpClient()
Dim url = "my url which return json"
Dim uri As New Uri(url)
Dim json As String = Await client.GetStringAsync(uri)
Dim j = JObject.Parse(json)("TIME SERIES INTRADAY")
Dim openPrice = j("1. open").Value(Of Double)
Diagnostics.Debug.WriteLine(openPrice)
Console.ReadLine()
End Sub
End Module
There is no issue when I build but when I run, I get this erroer message when I step on row
Dim json As String = Await client.GetStringAsync(uri)
error code:
The program '[4032] AVT.exe' has exited with code 0 (0x0).
Do you know why this line is returning this error?
Framework 4.5

You won't be able to do top-level Await in a console program. You can still make it work (preserving the Async on LoadData) with the following changes:
Change the signature of LoadData to Private Async Function LoadData() As Task
Change the call in Main to `LoadData.GetAwaiter().GetResult()
This will block in Main which is fine because there is no message loop to support a non-blocking wait. This is only appropriate in a console program, if you were doing this in any other setting your original implementation would have been correct (except that you should always use Async Function ... As Task in preference to Async Sub in any context aside from event handlers).

Yes, you can do this even in a console application.
I suggest you to use an ApplicationContext in order to keep all alive.
Doing as you shows, so, calling your LoadData()
your Main Sub going tasks are:
Enter
(and immediately after)
Exit
.
Take a look on code below to figure out the mechanism that you need to do what you want to do.
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json.Linq
Module Module1
Public Class MyApplicationContext
Inherits ApplicationContext
Private Async Sub LoadData()
Dim client As New Net.Http.HttpClient()
Dim url = "https://stackoverflow.com/questions/59324373/how-to-use-getstringasync-in-vb-net"
Dim uri As New Uri(url)
Dim json As String = Await client.GetStringAsync(uri)
Console.WriteLine(json)
Diagnostics.Debug.WriteLine(json)
'Dim j = JObject.Parse(json)("TIME SERIES INTRADAY")
'Dim openPrice = j("1. open").Value(Of Double)
'Diagnostics.Debug.WriteLine(openPrice)
Console.ReadLine() 'Here is stopped/waiting for user
'Here your application can be stopped after her work
'Application.Exit()
End Sub
Public Sub New()
MyBase.New()
AddHandler Application.ApplicationExit, AddressOf OnApplicationExit
LoadData()
End Sub
Private Sub OnApplicationExit(ByVal sender As Object, ByVal e As EventArgs)
Try
' delete your data here
Catch
End Try
End Sub
End Class
Public Sub Main()
Dim context As MyApplicationContext = New MyApplicationContext()
Application.Run(context)
End Sub
End Module

Related

How can I show my JSON results in a Textbox instead of writing to the Console?

I'm running into a little problem that I haven't found a way to to solve.
I haven't found a forum where this specific problem is addressed, I really hope to find some help.
Here is my code:
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json.Linq
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim request As HttpWebRequest
Dim response As HttpWebResponse = Nothing
Dim reader As StreamReader
request = DirectCast(WebRequest.Create("https://pastebin.com/raw/dWjmfW8N"), HttpWebRequest)
response = DirectCast(request.GetResponse(), HttpWebResponse)
reader = New StreamReader(response.GetResponseStream())
Dim jsontxt As String
jsontxt = reader.ReadToEnd()
Dim myJObject = JObject.Parse(jsontxt)
For Each match In myJObject("matches")
Console.WriteLine(match("http")("host").ToString)
Next
End Sub
End Class
Here is the output:
223.16.205.13
190.74.163.58
71.7.168.29
117.146.53.244
31.170.146.28
118.36.122.169
123.7.117.78
113.61.154.182
36.48.37.191
113.253.179.234
124.13.29.41
180.122.74.183
121.157.114.93
39.78.35.216
176.82.1.100
201.143.142.75
222.117.29.229
89.228.209.185
59.153.89.245
148.170.162.37
112.160.243.23
62.101.254.177
190.141.161.149
121.132.177.79
79.165.124.174
118.39.91.43
220.83.82.58
220.161.101.195
190.218.188.86
123.241.174.77
219.71.218.113
81.198.205.2
1.64.205.1
190.204.66.180
203.163.241.36
36.34.148.33
221.124.127.89
115.29.210.231
39.121.63.13
178.160.38.191
117.146.55.217
149.91.99.49
220.93.231.104
49.245.71.40
211.44.70.107
37.119.247.51
222.101.54.200
178.163.102.223
119.198.145.129
188.26.240.141
115.29.233.160
190.164.29.145
94.133.185.144
181.37.196.134
116.88.213.9
115.2.194.11
1.226.12.161
178.63.73.210
49.149.194.242
14.32.29.251
59.0.191.68
58.122.168.43
142.129.230.137
105.145.89.51
201.243.97.65
175.37.162.102
186.88.141.126
105.148.43.100
60.179.173.21
69.115.51.207
90.171.193.132
14.64.76.165
121.127.95.80
175.211.168.48
99.240.74.72
58.153.174.2
119.77.168.142
121.170.47.232
58.243.20.124
199.247.243.234
47.111.76.211
93.72.213.251
218.32.44.73
220.83.90.204
119.158.102.20
95.109.55.204
106.5.19.223
190.199.215.69
190.218.57.249
36.102.72.163
219.78.162.215
177.199.151.96
196.93.125.34
211.58.150.166
180.131.163.40
93.156.97.81
159.89.22.81
130.0.55.156
186.93.202.111
195.252.44.173
What I want to do is to transfer that console output to my Textbox1.Text. Can anyone please show me a way to solve this?
A somewhat simplified method, using WebClient's DownloadStringTaskAsync to download the JSON.
You don't need special treatment here, strings that represent IpAddresses are just numbers and dots and the source encoding is probably UTF8.
After that, just parse the JSON and Select() the property values you care about, transform the resulting Enumerable(Of JToken) to an array of strings and set the array as the source of a TextBox.Lines property.
You can store the lines collection for any other use, in case it's needed.
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using client As New WebClient()
Dim json = Await client.DownloadStringTaskAsync([The URL])
Dim parsed = JObject.Parse(json)
Dim lines = parsed("matches").
Where(Function(jt) jt("http") IsNot Nothing).
Select(Function(jt) jt("http")("host").ToString()).ToArray()
TextBox1.Lines = lines
End Using
End Sub
There's no need to transfer anything. If you want the data in a TextBox then put it in a TextBox. You can then output the same data using Console.WriteLine or Debug.WriteLine. You can use a loop:
Dim hosts As New List(Of String)
For Each match In myJObject("matches")
hosts.Add(match("http")("host").ToString())
Next
Dim text = String.Join(Environment.NewLine, hosts)
myTextBox.Text = text
Console.WriteLine(text)
You could also use LINQ:
Dim text = String.Join(Environment.NewLine, myJObject("matches").Select(Function(match) match("http")("host").ToString()))
myTextBox.Text = text
Console.WriteLine(text)
Alternative approach to display collection of things in Winforms are ListView, DataGridView or other collection controls depends on desired usage.
Add ListView control in designer and next code will fill it with received values.
Shared ReadOnly client As HttpClient = New HttpClient()
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim response As HttpResponseMessage =
Await client.GetAsync("https://pastebin.com/raw/dWjmfW8N")
response.EnsureSuccessStatusCode()
Dim jsonBody As String = Await response.Content.ReadAsStringAsync()
Dim myJObject = JObject.Parse(jsonBody)
ListView1.Items.Clear()
For Each match In myJObject("matches")
ListView1.Items.Add(match("http")("host").ToString)
Next
End Sub

"InvalidOperationException : Connection must be valid and open" On MySqlConnection

I was working on a VB.Net project (first time, I was previously working in VBA) and I seem to have trouble establishing connecion with a MariaDB/MySQL database.
I wanted to get all rows for one column to use it as source for a ComboBox named CBClient in a Form
Here my codes so far:
First class: ClassSQL
Imports MySql.Data.MySqlClient
Imports MySql.Data.Types
Public Class ClassSQL
Public Shared ConfigSQL As String =
"DATABASE=(My actual DB);DATA SOURCE=(IP of the server);USER ID=(UserID);PASSWORD=(Password)"
Public Shared ConnectDB As New MySqlConnection(ConfigSQL)
End Class
And the Form class:
Imports MySql.Data.MySqlClient
Public Class NewDossier
Private Sub NewDossier_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GetCBClient()
End Sub
Sub GetCBClient()
ClassSQL.ConnectDB.Open()
Dim Requete As String = "SELECT NomClient FROM MSClients"
Dim Query As New MySqlCommand(Requete, ClassSQL.ConnectDB)
Dim rs As MySqlDataReader = Query.ExecuteReader
Do While rs.Read
CBClient.Items.Add(rs.GetString("NomClient"))
Loop
ClassSQL.ConnectDB.Close()
End Sub
End Class
On ClassSQL.ConnectDB.Open() in the Form class I have the exception:
InvalidOperationException : Connection must be valid and open
Is my connection wrong somehow? Or is it something I did wrong?
Is there a way to specify the port?
In ADO.Net, it is not generally a good idea to try to re-use the same connection object throughout an application, because of a feature called Connection Pooling. The connector is already managing this for you. Instead, it really is better to just create a new connection instance for most queries. Just keep the connection string handy and re-use that. This works especially well in conjunction with the IDisposable/Using pattern.
Additionally, it's a good idea to put your queries in the same Class or Module as your connection string, isolated from the rest of the application, where each query is a function that returns the data and (usually) accepts an argument telling it what data to find.
Public Module SQL
'Making this private helps ensure you remember to put database activities here in this class.
Private ConnectionString As String = "DATABASE=(My actual DB);DATA SOURCE=(IP of the server);USER ID=(UserID);PASSWORD=(Password)"
'You could also design this function to return a DataTable object, if Iterator blocks aren't your thing
Public Iterator Function GetMSClients() As IEnumerable(Of String)
Dim Requete As String = "SELECT NomClient FROM MSClients"
Using cn As New MySqlConnection(ConnectionString), _
cmd As New MySqlCommand(Requete, cn)
cn.Open()
Using rdr As MySqlDataReader = cmd.ExecuteReader()
While rdr.Read()
Yield rdr.GetString("NomClient")
End While
End Using
End Using
End Function
End Module
Public Class NewDossier
Private Sub NewDossier_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CBClient.Items.AddRange(SQL.GetMSClients().ToArray())
End Sub
End Class

Programatically fill TFS New Bug workitem from VBA

I am wondering if it is possible to have VBA (Access) open a TFS Bug report webpage and fill in the description ?
While I am able to open the page I have not yet found a way to populate the description and potently other fields.
Perhaps one of the experts knows?
I wouldn't try to do what you are working on.
One, trusting a buggy application to correctly report its own bugs isn't a great idea. But beyond that you will be trying to attach Access to TFS.
That being said you can do this entirely automated. Put in some error trapping and then what you are looking to do is how to call TFS APIs. But you may or may not have to install some third part tools etc.
Starting point TFS API
The way I finally did it is to use a dll to interface between access and tfs...
For anyone trying to do the same here is the code...
Imports Microsoft.TeamFoundation.Client
Imports Microsoft.TeamFoundation.WorkItemTracking.Client
Imports Microsoft.TeamFoundation.WorkItemTracking.Common
Imports System.Runtime.InteropServices
<ComClass(TFSInterOp.ClassId, TFSInterOp.InterfaceId, TFSInterOp.EventsId)> Public Class TFSInterOp
Public Const ClassId As String = "14306fc5-1492-42d6-a032-bc4348508dd3"
Public Const InterfaceId As String = "288339cb-0c2e-45fd-8005-e5fed401f0cc"
Public Const EventsId As String = "723327dc-7777-44e4-b291-9299027665eb"
Public Sub New()
End Sub
Public Function InsertBugWorkItem(Title As String, Desc As String) As String
Dim tfsServer As String = My.Settings("TfsFullPath").ToString ' {YOUR TFS SERVER PATH}
Dim strAssUser As String = My.Settings("AssignTo").ToString
Dim teamFoundationServer1 As Microsoft.TeamFoundation.Client.TfsTeamProjectCollection = Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory.GetTeamProjectCollection(New Uri(tfsServer))
Dim workItemStore1 As New WorkItemStore(teamFoundationServer1)
teamFoundationServer1.Authenticate()
Dim WorkItemStore As WorkItemStore = New WorkItemStore(tfsServer)
Dim tfsProject As Project = WorkItemStore.Projects(0)
Dim wIType As WorkItemType = tfsProject.WorkItemTypes("Bug")
Dim workItem As WorkItem = New WorkItem(wIType)
Dim wiStore = teamFoundationServer1.GetService(Of WorkItemStore)()
Dim Project = wiStore.Projects
Dim Area = Project.Item(0).AreaRootNodes("BITS").Id ' The project to add the work item to
' Prefill items
workItem.Title = Title
workItem.Description = Desc
workItem.AreaId = Project.Item(0).AreaRootNodes("BITS").Id
workItem.Fields("Assigned To").Value = strAssUser
workItem.Fields("System Info").Value = "Access V 1.1.25"
workItem.Fields("Repro Steps").Value = Desc
Dim result As ArrayList = workItem.Validate()
If result.Count > 0 Then
Return (result(0).ToString + "There was an error adding this work item to the work item repository")
Else
workItem.Save()
End If
' Open the new item in explorer
Dim myService = teamFoundationServer1.GetService(Of TswaClientHyperlinkService)()
Dim myUrl = myService.GetWorkItemEditorUrl(workItem.Id)
Dim oProcess As New System.Diagnostics.Process()
oProcess.StartInfo.FileName = myUrl.ToString
oProcess.Start()
Return "OK"
End Function
End Class

ServiceStack.Text reading json results not working

I am just trying to figure out the best way to deserialize a json string returned from a 3rd party api call. I read ServiceStack is fast so want to try it out. No experience and here is what I have done:
Opened Visual Studio 2013
Created new project Windows Forms Application
Installed ServiceStack.Text (based on https://servicestack.net/download)
Added a button (btnView) and textbox (txtOutput)
Add code to btnView_Click event
Private Sub btnView_Click(sender As Object, e As EventArgs) Handles btnView.Click
Me.Cursor = Cursors.WaitCursor
Dim wp As New WebPost 'this allows to pass url and return results
wp.URL = "xxxx"
Dim sJSONRetVal As String = wp.Request(String.Empty, True)
'sJSONRetVal return values looks like the following:
'{"complaints":[{"feedback_type":"abuse","subject":"Sales Agent Position"},{"feedback_type":"abuse","subject":"Sales Agent Position"}],"message":"OK","code":0}
'ServiceStack.Text example
Dim t As SMTP_Complaints = ServiceStack.Text.JsonSerializer.DeserializeFromString(Of SMTP_Complaints)(sJSONRetVal)
'For Each xi As SMTP_Complaints In t
' txtOutput.Text &= xi.mail_from & vbCrLf
'Next
wp = Nothing
txtOutput.Text = t.ToString
Me.Cursor = Cursors.Default
End Sub
Public Class SMTP_Complaints
Dim _feedback_type As String = ""
Dim _subject As String = ""
Public Property feedback_type As String
Get
Return _feedback_type
End Get
Set(value As String)
_feedback_type = value
End Set
End Property
Public Property subject As String
Get
Return _subject
End Get
Set(value As String)
_subject = value
End Set
End Property
End Class
The above doesn't seem to get any data. how would I loop through the data returned and return the data from both instances? Just not sure how I need to set this up to read the json data and then be able to output.
Based on the returned JSON of:
{"complaints":[{"feedback_type":"abuse","subject":"Sales Agent Position"},{"feedback_type":"abuse","subject":"Sales Agent Position"}],"message":"OK","code":0}
You will need two DTOs to deserialise this result.
I have used auto implemented properties here to simplify the complexity of the code. If you use an older version of VB, you'll need to expand these out to include a backing field with get and set method.
Public Class SMTP_Complaint
Public Property feedback_type As String
Public Property subject As String
End Class
Public Class SMTP_ComplaintsResponse
Public Property complaints As SMTP_Complaint()
Public Property message As String
Public Property code As Integer
End Class
You need the SMTP_ComplaintsResponse class because your complaints are wrapped in your JSON response.
Then to deserialise the response:
Dim response = JsonSerializer.DeserializeFromString(Of SMTP_ComplaintsResponse)(sJSONRetVal)
And your complaints are then accessible:
For Each complaint As var In response.complaints
Console.WriteLine("Type: {0}, Subject {1}", complaint.feedback_type, complaint.subject)
Next

writing to file using Script task in SSIS 2005 not working

could anybody give me any clue why this script not doing the job to write the file?
in fact when i'm trying to run it on SSIS 2005, the task showed up green and success
I'm confused
Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Runtime
Imports System.IO
Public Class ScriptMain
Public Sub Main()
System.IO.File.AppendAllText("e:\test.txt","<![CDATA[ <b>Sales</b>]]>")
Dts.TaskResult = Dts.Results.Success
End Sub
End Class
Thank you in advance
Looks like there is a problem passing in the XML. Try the following and see if that works, if so, then the XML fragment you are adding is the issue.
Public Sub Main()
Dim strFile As String
Dim strText As String
strFile = "e:\test.txt"
strText = "test"
Try
File.AppendAllText(strFile, strText)
Catch e As Exception
Dts.TaskResult = Dts.Results.Failure
End Try
Dts.TaskResult = Dts.Results.Success
End Sub