I'm attempting to parse a response from the USPS CityStateLookup API and I don't appear to be modelling it properly, as I'm getting an "{"Unexpected character encountered while parsing value: <. Path '', line 0, position 0."}" while parsing" error right at the beginning of the DeserializeObject call
My code is:
Class CityStateLookupResponse
Property ZipCodeList As List(Of ZipCode)
End Class
Class ZipCode
Property Zip5 As String
Property City As String
Property State As String
End Class
Private Async Function GetCityStateFromZipAsync(byval Zip5Code as string) as threading.tasks.task(of CityStateLookupResult)
Dim result As New CityStateLookupResponse
Dim client As New HttpClient() With {
.BaseAddress = New Uri("http://production.shippingapis.com/ShippingAPI.dll")
}
Dim arguments As String = "?API=CityStateLookup&XML=<CityStateLookupRequest USERID=""{0}""><ZipCode ID= ""{1}""><Zip5>{2}</Zip5></ZipCode></CityStateLookupRequest>"
arguments = String.Format(arguments, "<My User ID>", 0, Zip5Code)
response = Await client.GetAsync(arguments)
If Not response.IsSuccessStatusCode Then
Return result
End If
myContent = Await response.Content.ReadAsStringAsync
' vvvv THIS IS THE ERROR LINE vvvv
result = Newtonsoft.Json.JsonConvert.DeserializeObject(Of CityStateLookupResponse)(myContent)
end function
The returned XML for the same API call in a browser is:
<CityStateLookupResponse>
<ZipCode ID="0">
<Zip5>55016</Zip5>
<City>COTTAGE GROVE</City>
<State>MN</State>
</ZipCode>
</CityStateLookupResponse>
What am I doing wrong in the class definition for CityStateLookupResponse? (Or is there a better way to go about this altogether?)
Haven't looked at VB in a while but it appears you are using the wrong method for deserializing XML. The method you are using is meant for JSON.
For XML deserialization use DeserializeXmlNode.
Related
I'm trying to upload a file with some metadata to a Web API. Everything is fine within the developer environment. But when the same API is hosted in Azure I get the following date parsing error:
Conversion from string "31/03/2019 11:33:52" to type 'Date' is not valid.
I guess StringContent should write the date on ISO 8601 format and it does not.
Next is a simplification of my procedure:
Public Async Function UploadDocFile(oHttpClient as HttpClient, url as string, ByVal oByteArray as Byte(), exs As List(Of Exception)) As Task(Of Boolean)
Dim retval As Boolean
Dim formContent = New Net.Http.MultipartFormDataContent From {
{New Net.Http.StringContent("DateCreated"), now},
{New Net.Http.StreamContent(New IO.MemoryStream(oDocfile.Stream)), "pdf", "pdf.jpg"}
}
Dim response = Await oHttpClient.PostAsync(url, formContent)
If response.StatusCode = 200 Then
retval = True
Else
exs.Add(New Exception(response.ReasonPhrase))
End If
Return retval
End Function
You are using a Collection Initializer to add items to the MultipartFormDataContent; you're expected to follow this overload of the Add method, which accepts two parameters of type HttpContent and String, respectively.
Thus, the second value enclosed in the braces ({}) should be the name of the data content, not its value. On the other hand, the parameter passed to the StringContent constructor should be the value (content), not the name. You basically have them swapped out. If you'd had Option Strict set to On (which is something you should do, BTW), you would've gotten a compiler error and would've easily identified the mistake.
Your code should look something like this:
Dim formContent = New Net.Http.MultipartFormDataContent From
{
{New Net.Http.StringContent(Now.ToString("SomeFormat")), "DateCreated"},
' More values.
}
..where SomeFormat is a format supported by the web API that you're using.
I need to pass itemNumber1 value as 075/458
http://localhost:8080/projectroot/some/itemNumber=075%2F458
or
http://localhost:8080/projectroot/some/itemNumber=075/458
But this is not hitting my controller method:
#RequestMapping("/some/{number}")
public #ResponseBody void getSomething(
#MatrixVariable(required = true) String itemNumber1,
#MatrixVariable(required = false) String itemNumber2,
#MatrixVariable(required = false) String itemNumber3)
I see that you are trying to parse it via the URL, but you are trying to get it by #ResponseBody. If you are using GET method to parse the value, your response body will be empty. If you try to get the data via response body, try the POST method instead.
I have a VB.NET function as below:
Public Shared Async Function GetIdDoc() As Task(Of String)
Dim result As String = ""
'Dim Uri As String = "http://localhost:53917/api/Documenti/GetNextIdDocumenti"
Dim Uri As String = apiUri & ApiEndPoints.GetNextIdDocumenti
Using client = New HttpClient()
Using response = Await client.GetAsync(Uri)
If response.IsSuccessStatusCode Then
Dim DocumentiIDJsonString = Await response.Content.ReadAsStringAsync()
result = DocumentiIDJsonString.ToString()
End If
End Using
End Using
Return result
End Function
I'm trying to return the Document ID from the DB but I'm getting
System.Threading.Tasks.Task`1[System.String]
Where actually it should return "2". Please help me on this: what am I doing wrong with this function?
Update
here is the function called:
txtIDDoc_Detail.Text = ApiData.GetIdDoc().ToString()
But inside the textbox I'm getting the above text. thanks.
I'm from C# but should work the same. In newer .Net Versions (>= 4.5) async/await is implemented. So if a method is marked as async and returns a Task (which should always be the case), you need to await it. This implicate that you have to mark your Method as async too. So your call should look like this:
txtIDDoc_Detail.Text = await ApiData.GetIdDoc();
The await waits till the long running Task is ready and returns it's inner value. All async Methods should return Task. If the Method is void it would be Task. Else it could be Task<int> or any other type. So await it and you can keep running ;)
#Sebi gives a great explanation of how to properly use async and await in this case, but I'm going to expand on exactly why you are getting the result that you see.
txtIDDoc_Detail.Text = ApiData.GetIdDoc().ToString()
Is returning
System.Threading.Tasks.Task`1[System.String]
Because you are calling .ToString on the instance of the Task Task(Of String), not the actual result. Types that don't override .ToString inherit the behavior of Object, which just returns the name of the type as a string.
You probably want this (asynchronous call):
txtIDDoc_Detail.Text = await ApiData.GetIdDoc()
Or this (synchronous call):
txtIDDoc_Detail.Text = ApiData.GetIdDoc().Result
Either of these calls will actually result of the task after it has completed.
As part of a SSIS (2005) package I am calling a RESTful API through a script component (VB.NET). I am getting the records back OK. The problem I have though is processing the format it comes back in so I can output it (split into the separate output columns) within the data flow and write into a SQL table. Don't know where to start - anyone got any ideas? I have no control over the API so am stuck with this format.
Here is the schema as per the API documentation:
{StatusMessage : <string>, Unit : <string> [ { VehicleID : <int>, RegistrationNumber : <string>, DistanceTravelled : <double>} ] }
And here is a sample of the data returned (it comes back as a single line of text):
{"VehicleDistance":
[
{
"VehicleId":508767,
"RegistrationNumber":"BJ63 NYO",
"DistanceTravelled":0.09322560578584671
},
{
"VehicleId":508788,
"RegistrationNumber":"BJ63 NYL",
"DistanceTravelled":6.1591048240661621
},
{
"VehicleId":508977,
"RegistrationNumber":"PE12 LLC",
"DistanceTravelled":60.975761413574219
},
{
"VehicleId":510092,
"RegistrationNumber":"BJ64 FCY",
"DistanceTravelled":14.369173049926758
},
{
"VehicleId":510456,
"RegistrationNumber":"BJ63 NYY",
"DistanceTravelled":4.04599142074585
},
{
"VehicleId":513574,
"RegistrationNumber":"BL64 AEM",
"DistanceTravelled":302.150390625
}
],
"StatusMessage":null,
"Unit":"imperial",
"HttpStatus":200
}
This is Javscript Object Notation AKA JSON and you need to deserialise it. The problem is that using SSIS is tricky with third party tools that are popular (and fast) but VB.Net actually has a built in class to serialise and deserialise JSON called JavaScriptSerializer
First add a Reference to your project called System.Web.Extensions and then you can use the JavaScriptSerializer to deserialise your JSON.
I've put your JSON in a file for easier handling so first I have to...
Dim sJSON As String = ""
Using swReadFile As New System.IO.StreamReader("E:\JSON.txt")
sJSON = swReadFile.ReadToEnd()
End Using
The rest is the pertinent bit, so first add 2 Imports...
Imports System.Collections.Generic
Imports System.Web.Script.Serialization
Then for example we can...
Dim lvSerializer As JavaScriptSerializer = New JavaScriptSerializer()
lvSerializer.MaxJsonLength = 2147483644
Dim dictParsedJSONPairs As Dictionary(Of String, Object) = lvSerializer.Deserialize(Of Dictionary(Of String, Object))(sJSON)
If dictParsedJSONPairs.ContainsKey("VehicleDistance") AndAlso _
TypeOf dictParsedJSONPairs("VehicleDistance") Is ArrayList Then
Dim ArrayEntries As ArrayList = DirectCast(dictParsedJSONPairs("VehicleDistance"), ArrayList)
For Each ArrayEntry As Object In ArrayEntries
Dim DictEntry As Dictionary(Of String, Object) = DirectCast(ArrayEntry, Dictionary(Of String, Object))
If DictEntry.ContainsKey("VehicleId") Then Console.WriteLine("VehichleId:" & DictEntry("VehicleId"))
Next
End If
If dictParsedJSONPairs.ContainsKey("Unit") Then
Console.WriteLine("Unit is " & dictParsedJSONPairs.Item("Unit"))
End If
Clearly you should research JSON before launching into serious use. The object can be nested JSON (i.e. Dictionary(Of String, Object)), a number of some sort, a string or an ArrayList
It could be a bit late but you may want to have a look at json.net from Newtonsoft (website). The component provided contains .Net 2.0 version.
Using it in a SSIS script task is quite simple. I did it in SSIS2008 based on .Net 3.5 to parse JSON string like below. And according to the document, it should work for .Net 2.0 version as well.
//I assume you had obtained JSON in string format
string JasonBuffer;
//define Json object
JObject jObject = JObject.Parse(JasonBuffer);
//In my example the Json object starts with result
JArray Results = (JArray)jObject["result"];
//loop the result
foreach (JObject Result in Results)
{
//for simple object
JObject joCustomer = (JObject)Result["Customer"];
//do something...
//for complex object continue drill down
foreach (JObject joSection in Result["Sections"])
{
foreach (JObject joDepartment in joSection["Departments"])
{
foreach (JObject joItem in joDepartment["Items"])
{
}
You can find some actual code here: link
I am very new to vb/.net and I'm trying to do something that I can do easily in classic vb. I want to get the source html for a webpage from the URL.
I'm using vb.net in Visual Studio Express for Windows 8.
I've read loads of stuff that talk about HttpWebRequest, but I can't get it to work properly.
I did at one point have it returning the html header, but I want to content of the page. Now, I can't even get it back to giving me the header. Ultimately, I want to process the html returned which I'll do (to begin with) the old-fashioned way and process the returned html as a string, but for now I'd like to just get the page.
The code I've got is:
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(New Uri(URL))
txtHTML.Text = request.GetRequestStreamAsync().ToString()
Can anyone help me with an example to get me going please?
You're trying to use an Async method in a synchronous way, which won't make any sense. If you're using .NET 4.5, you can try marking the calling method with Async and then using the Await keyword when calling GetRequestStreamAsync.
Public Sub MyDownloaderMethod()
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest
= System.Net.HttpWebRequest.Create(New Uri(URL))
' Use the Await keyword wait for the async task to complete.
Dim response = request.GetResponseAsync()
txtHTML.Text = response.GetResponseStream().ToString()
End Function
See the following MSDN article for more information on async programming with the Await keyword: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
Edit
You are receiving your error because you're trying to get the Request stream (what you send the server), and what you really want is the Response stream (what the server sends back to you). I've updated my code to get the WebResponse from your WebRequest and then retrieve the stream from that.
Public Shared Function GetWebPageString(ByVal address As Uri) As String
Using client As New Net.WebClient()
Return client.DownloadString(address)
End Using
End Function
There is also DownloadStringAsync if you don't want to block
request.GetRequestStreamAsync() is probably not a method. I think you're cribbing code from a site where someone wrote their own add-on methods to HttpWebRequest. Try request.GetResponse() to return a response object, then in the response object you can inspect the stream and convert it to text if you need to.
This worked for me in VB.Net 4.5
Public Async Sub GetHTML()
Dim PageHTML as string
Dim client As New HttpClient
Dim getStringTask As Task(Of String) = client.GetStringAsync(PageURL)
PageHTML = Await getStringTask
MsgBox(PageHTML)
End Sub