Get items in response object via javaScriptSerializer.Deserialize - asp.net

I have a dropbox webhook hitting my page. I need to grab the list of users in the response which I will process later on a separate thread. I can see the users in the data variable but I don't know how to extract the list of users in the object. Basically I want to populate an array of users which I can loop through and do some other processing. Hope this makes sense.
This is what the object looks like:
{
"delta": {
"users": [
12345678,
23456789,
...
]
}
}
This is the code I tried and like I say, I can see the string in data:
Dim strJSON = [String].Empty
Context.Request.InputStream.Position = 0
Using inputStream = New StreamReader(Context.Request.InputStream)
strJSON = inputStream.ReadToEnd()
End Using
Dim javaScriptSerializer As New JavaScriptSerializer()
Dim data As Object = javaScriptSerializer.Deserialize(strJSON, GetType(Object))
I would like an array of the users. Hope you can help.

Just make some classes for your response data:
Class Data
Public Property delta As Delta
End Class
Class Delta
' If you would rather have a list you can declare this As List(Of Integer) instead
Public Property users As Integer()
End Class
You can then deserialize directly into the classes:
Dim data As Data = javaScriptSerializer.Deserialize(Of Data)(strJSON)
From there you can work with your data easily enough:
For Each user As Integer In data.delta.users
Console.WriteLine(user)
Next

Related

Access VB property based on name as string - Fastest Option

I'm developing an ASP.NET MVC web app in VB and I am required to output a set of data to a table format, and to allow the user to configure the order and presence of columns from an available set. The data set is stored as a list of the object type representing the row model.
Currently, I implement this using CallByName. Iterating over an ordered list of property names and outputting the value from the instance of the row model. However, based on testing this seems to be a major bottleneck in the process.
I've seen a recommendation to store delegates to get the property, against the string representation of the property's name. So, I can presumably do something like this:
Public Delegate Function GetColumn(ByRef RowObj As RowModel) As String
Dim GetPropOne As GetColumn = Function(ByRef RowObj As RowModel) RowObj.Prop1.ToString()
Dim accessors As New Hashtable()
accessors.Add("Prop1", GetPropOne)
Then, loop through and do something like this:
Dim acc As GetColumn = accessors(ColumnName)
Dim val As String = acc.Invoke(currentRow)
It looks faster, but it also looks like more maintenance. If this is indeed faster, is there a way I can dynamically build something like this? I'm thinking:
Public Delegate Function GetObjectProperty(Instance As Object) As Object
For Each prop In GetType(RowModel).GetProperties()
Dim acc As GetObjectProperty = AddressOf prop.GetValue
columns.Add(prop.Name, acc)
Next
Dim getColVal As GetObjectProperty = columns(ColumnName)
Dim val As String = getColVal.Invoke(currentRow).ToString()
Open to suggestions for different approaches.
I do a similar thing to turn a SOAP response into a Data Table
Public Function ObjectToDataSource(objName) As DataSet
Dim CollName = ""
Dim ds As New DataSet()
For Each m As System.Reflection.PropertyInfo In objName.GetType().GetProperties()
If m.CanRead Then
If InStr(m.PropertyType.ToString, "[]") <> 0 Then
CollName = m.Name
Exit For
End If
End If
Next
Dim CollObj
CollObj = CallByName(objName, CollName, CallType.Get)
If CollObj.length = 0 Then
Call EndTask("No Supply Chains to display", "Royal Mail failed to return Supply Chain information for these credentials", 3)
Else
Dim dt_NewTable As New DataTable(CollName)
ds.Tables.Add(dt_NewTable)
Dim ColumnCount = 0
For Each p As System.Reflection.PropertyInfo In CollObj(0).GetType().GetProperties()
If p.CanRead Then
If p.Name <> "ExtensionData" Then
dt_NewTable.Columns.Add(p.Name, p.PropertyType)
ColumnCount = ColumnCount + 1
End If
End If
Next
Dim rowcount = CollObj.Length - 1
For r = 0 To rowcount
Dim rowdata(ColumnCount - 1) As Object
For c = 0 To ColumnCount - 1
rowdata(c) = CallByName(CollObj(r), dt_NewTable.Columns.Item(c).ToString, CallType.Get)
Next
dt_NewTable.Rows.Add(rowdata)
rowdata = Nothing
Next
End If
Return ds
End Function
This is specific to my needs in terms of getting CollName and not requiring ExtensionData
If ColumnName is the same name as one of the RowModel's properties I don't see why you need the long workaround with delegates...
An extension method which gets only the property you want right now is both faster and consumes less memory.
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Function GetProperty(ByVal Instance As Object, ByVal PropertyName As String, Optional ByVal Arguments As Object() = Nothing) As Object
Return Instance.GetType().GetProperty(PropertyName).GetValue(Instance, Arguments)
End Function
End Module
Example usage:
currentRow.GetProperty("Prop1")
'or:
currentRow.GetProperty(ColumnName)

Visual basic and Json.net Web request

Basically what im trying to do is make a program that list game information for league of legends.. using there API to extract data. how this works is you Search there username and it returns an integer linked to that account, you then use that integer to search for all of the information for that account, EG account level, wins, losses, etc.
I've run into a problem i can't seem to figure out.. Please not that I'm very new to Json.net so have little experience about working with it.. Below is how the search for the user ID is found, The First section is the Username Minus Any spaces in the name the next is the ID which is the information i require.
{"chucknoland":{"id":273746,"name":"Chuck Noland","profileIconId":662,"summonerLevel":30,"revisionDate":1434821021000}}
I must be declaring the variables wrong in order to obtain the data as everything i do it returns as 0.
these are the following class i have to store the ID within
Public Class ID
Public Shared id As Integer
Public Shared name As String
End Class
Looking at a previous example seen here Simple working Example of json.net in VB.net
They where able to resolve there issue by making a container class with everything inside it.. My problem is that The data i seek i always changing.. The first set will always be different to the "Chucknoland" that's displayed in the example.. is someone able to explain how i could go about extracting this information?
Please note that the variables rRegion has the value of what server there on, Chuck Noland is on OCE, and sSearch is the Username.. Due to Problems with API keys i had to remove the API key from the code... But the URL returns the Json Provided.
'URL string used to grab Summoner ID
jUrlData = "https://oce.api.pvp.net/api/lol/" + rRegion + "/v1.4/summoner/by-name/" + sSearch +
' Create a request for URL Data.
Dim jsonRequest As WebRequest = WebRequest.Create(jUrlData)
'request a response from the webpage
Dim jsonResponse As HttpWebResponse = CType(jsonRequest.GetResponse(), HttpWebResponse)
'Get Data from requested URL
Dim jsonStream As Stream = jsonResponse.GetResponseStream()
'Read Steam for easy access
Dim jsonReader As New StreamReader(jsonStream)
'Read Content
Dim jsonResponseURL As String = jsonReader.ReadToEnd()
jUrlString = jsonResponseURL
this is the request i have to obtain the information, and this is the code i tried to use to display the ID for that json.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim obj As ID
obj = JsonConvert.DeserializeObject(Of ID)(jUrlString)
MsgBox(obj.id)
End Sub
Is anyone able to explain how i can go about getting this to work?
One way to handle this would be to get the item into a Dictionary where the keys are the property names.
The class you have is not quite right unless you only want name and id and not the rest of the information. But using a Dictionary you wont need it anyway. The "trick" is to skip over the first part since you do not know the name. I can think of 2 ways to do this, but there are probably more/better ways.
Since json uses string keys pretty heavily, create a Dictionary, then get the data from it for the actual item:
jstr = ... from whereever
' create a dictionary
Dim jResp = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(jstr)
' get the first/only value item
Dim jobj = jResp.Values(0) ' only 1 item
' if you end up needing the name/key:
'Dim key As String = jResp.Keys(0)
' deserialize first item to dictionary
Dim myItem = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(jobj.ToString)
' view results
For Each kvp As KeyValuePair(Of String, Object) In myItem
Console.WriteLine("k: {0} v: {1}", kvp.Key, kvp.Value.ToString)
Next
Output:
k: id v: 273746
k: name v: Chuck Noland
k: profileIconId v: 662
k: summonerLevel v: 30
k: revisionDate v: 1434821021000
Using String, String may also work, but it would convert numerics to string (30 becomes "30") which is usually undesirable.
While poking around I found another way to get at the object data, but I am not sure if it is a good idea or not:
' parse to JObject
Dim js As JObject = JObject.Parse(jstr)
' 1 = first item; 2+ will be individual props
Dim jT As JToken = js.Descendants(1)
' parse the token to String/Object pairs
Dim myItem = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(jT.ToString)
Same results.

insert json jObject data into labels and textboxes

My problem is as follows:
I have a Public sub created which looks like this for the moment:
Public Sub eniroContacts()
Dim phone As String = newCustPhone1.text
Dim url As String = "http://bedrift.telefonkatalogen.no/tk/search.php?qry=" + phone + "&from=1&to=27&format=json&username=user&password=pw"
Dim request As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
Dim o As JObject = JObject.Parse(reader.ReadToEnd)
lblMsg.Text = o.ToString
reader.Close()
response.Close()
End Sub
so far so good and my lblMsg.Text displays the json string i want to get my data from (formatted for clarity):
{
"qry": "92020945",
"result": {
"hitLinesBeforeFilter": 1,
"userID": 299228,
"1": {
"listing": {
"table": "listing",
"id": "3647950",
"duplicates": [{
"table": "listing",
"id": "3647950:0",
"idlinje": "E19CMOD",
"tlfnr": "99887766",
"etternavn": "Omnes",
"fornavn": "Martin",
"veinavn": "Highway",
"husnr": "20",
"postnr": "0601",
"virkkode": "P",
"apparattype": "M",
"telco": "TM",
"kilde": "E",
"bkdata": "M",
"prioritet": "0",
"fodselsdato": "1976-07-03",
"kommunenr": "301",
"poststed": "Oslo",
"kommune": "Oslo",
"fylke": "Oslo",
"landsdel": "Ø"
}]
}
},
"dummy": null
}
}
What I want to do now is to actually fetch some of the values in the string and put them into some of my textboxes and labels, but don't have a clue on how can I do that. For example, I would want the values "fornavn", "tlfnr" and "fylke". The values are Martin, 99887766 and Oslo in this example, which should be put in textbox1, 2 and 3.
Also i would like to add that some of the Fields may not be there on some searched, like the first name ("fornavn" in my example). When this isnt there and i try writing:
Dim fornavn = o("result")("1")("listing")("duplicates")(0)("fornavn")
it crashes. Something i can do to prevent this in these scenarios?
Any clues and tips are very appreciated! :)
The easiest thing would be using directly the property names and array indexes (from json.net docs). Something like this:
Dim fornavn = o("result")("1")("listing")("duplicates")(0)("fornavn")
It looks like the number of results and duplicates in the response will change between different responses, so you may not be able to hardcode it like that (For example, you may need to check first that result has at least one item and also that duplicates has at least one item)
Another approach would be to deserialize the string into strongly typed .Net objects. You would create your .Net classes that mirror the json structure and tell json.net to convert the json string into .Net object instances of those classes. See the json.net docs. This requires more work as you need to create the .Net classes and you will need to understand the deserialization process. If you want to explore this option, have a look at this and this other questions.
Edit
Given the json structure, it might be easier to manually get the properties like "1" inside the result property in the json object.
Then you have the options to either manually continue drilling in the object and iterating over the duplicates, applying whatever logic you require, or deserialize into .Net objects.
The following code will get the result property, iterate over all its properties with keys 1,2, etc and print the name in every duplicate using both approaches:
Sub Main()
Dim JsonStr = "... the json string ..."
Dim o As JObject = JObject.Parse(JsonStr)
Dim results = o("result")
For Each resultProperty In results.Value(Of JObject)()
'Only get properties like "1" inside the root "result" property
If Not Integer.TryParse(resultProperty.Key, Nothing) Then Continue For
'Approach 1: Manually Iterate over the duplicates array inside each result
Dim duplicatesArray = resultProperty.Value("listing")("duplicates").Value(Of JArray)()
For Each duplicate In duplicatesArray
'Make sure there is a fornavn property
If duplicate("fornavn") Is Nothing Then Continue For
Console.WriteLine(duplicate("fornavn"))
Next
'Approach 2: Deserialize the listing into a .Net object
Dim serializer As JsonSerializer = New JsonSerializer()
Dim resultObject As Result = JsonConvert.DeserializeObject(Of Result)(resultProperty.Value.ToString())
For Each duplicateObject In resultObject.listing.duplicates
Console.WriteLine(duplicateObject.fornavn)
Next
Next
Console.ReadKey()
End Sub
Class Result
Property listing As Listing
End Class
Class Listing
Property table As String
Property id As String
Property duplicates As Duplicate()
End Class
Class Duplicate
Property table As String
Property id As String
Property idlinje As String
Property fornavn As String
'Continues with all the other properties...
End Class
Please note I just quickly wrote this code, so you might need to adjust it if some properties are not always present in the json response.

dynamically change querystring in asp.net

Our client is asking to encrypt the URL because it is passing values in the query string. We have used encryption and are able to encrypt the URL; however, existing code uses querystring["var"] in so many places and fails because of the encrypted URL. Hence, on page load, we will have to decrypt the URL. If I decrypt and alter the query string using response.redirect, then again query string will be visible in the URL and can be misused.
Please help.
EDIT
I was reading about RESTfull web service. I have not yet understood entire concept. I wonder if I can use this with my application to hide query string. Please let me know if so.
Thanks.
One way to achieve this with little headache is to decrypt the query string as you currently do, then set its values to some object which can be stored in the session. Storing it in a session variable would be useful if you wanted to exclude this information (hide) from the query string - you'd essentially be passing the data around behind the scenes.
Once stored in session, you would then change your code, such that wherever you use querystring["var"], you will instead refer to the object that has been stored in the session.
Edit
Note, though, that this doesn't have to be relegated to a single value. This object can have multiple properties each representing a query string value:
MyQueryStringObject myQueryStringObject = new MyQueryStringObject(SomeUrl);
//MyQueryStringObject decrypts the query string and assigns the values to properties in its constructor
string abc = myQueryStringObject.abc;
string xyz = myQueryStringObject.xyz;
Now, that uses properties to represent each query string value. You may have tons of them. In that case, you can store the values into some sort of Dictionary or a NameValueCollection perhaps.
There are various ways to achieve this which I think is beyond topic, but, note that the key to all of this, the very essence is to simply decrypt the url on the server (during postback) and save the unencrypted data into a session variable should you want to hide it from the URL.
There is a much better way of going about this. I deal with a client with that has the same requirement. This class has soared through security scans as well.
Public Class QueryStringManager
Public Shared Function BuildQueryString(ByVal url As String, ByVal queryStringValues As NameValueCollection) As String
Dim builder As New StringBuilder()
builder.Append(url & "?")
Dim count = queryStringValues.Count
If count > 0 Then
For Each key In queryStringValues.AllKeys
Dim value As String = queryStringValues(key)
Dim param As String = BuildParameter(key, value)
builder.Append(param)
Next
End If
Return builder.ToString()
End Function
Public Shared Function DeconstructQueryString(ByVal Request As HttpRequest) As NameValueCollection
Dim queryStringValues As New NameValueCollection
For Each key In Request.QueryString.AllKeys
Dim value As String = Request.QueryString(key)
value = DeconstructParameter(value)
queryStringValues.Add(key, value)
Next
Return queryStringValues
End Function
Private Shared Function BuildParameter(ByVal key As String, ByVal value As String) As String
Dim builder As New StringBuilder()
builder.Append(key.ToString() & "=")
value = GetSafeHtmlFragment(value)
Dim encrypt As Security = New Security()
value = encrypt.Encrypt(value)
builder.Append(value)
builder.Append("&")
Return builder.ToString()
End Function
Public Shared Function DeconstructParameter(ByVal value As Object) As String
Dim decrypt As New Security()
value = decrypt.Decrypt(value)
value = GetSafeHtmlFragment(value)
End Function
End Class
Use
Dim nvc As NameValueCollection = New NameValueCollection()
nvc.Add("value", 1)
Dim builtUrl As String = QueryStringManager.BuildQueryString(url, nvc)
Response.Redirect(builtUrl, false);
Then when you get to the page you simply write:
Dim decryptedValues As NameValueCollection = QueryStringManager.DeconstructQueryString(Request)
The reason why I use NameValueCollection is because that's the same type as QueryString. You can build on to the class to add an object into the QueryString based on it's properties and their values as well. This keeps all of the complex and tedious logic encapsulated away.

Save changes to Entity model to the database

I'm new to Entity Framework and am expanding an existing codebase. I'm using jQuery to pass the needed info back to the server ajaxy style, so I can't use TryUpdateModel(). Here's the code:
<HttpPost()>
Function UpdateRoster() As JsonResult
Dim model As New Models.ViewModels.PlayerAdmin
Dim jsonString As String = Request.Form("json")
model = Deserialise(Of Models.ViewModels.PlayerAdmin)(jsonString)
For Each playerAdminPlayer As Models.ViewModels.PlayerAdminPlayer In model.Roster
Dim playerToTeam As New DAL.PlayersToTeam
Dim player As DAL.Player = PlayerAdminManager.GetPlayerById(playerAdminPlayer.PlayerId)
player.FirstName = playerAdminPlayer.FirstName
PlayerAdminManager.SaveChanges()
Next playerAdminPlayer
Dim playerAfter As DAL.Player = PlayerAdminManager.GetPlayerById(model.Roster.First.PlayerId)
Return Json(New With {.success = False, .message = playerAfter.FirstName})
End Function
Deserialise is a helper function that converts the incoming JSON string to a vb object.
Things seem to work fine in that player successfully loads from the DB and playerAdminPlayer is the correct object from the JSON string. However, when I call PlayerAdminManager.SaveChanges() (which just passes the call the db.SaveChanges() the result is always 0, even if there is a change (not sure if that is expected).
playerAfter was my attempt to see if changes were actually being saved. It seems to work correctly, in that playerAfter.FirstName is the newly updated first name.
PlayerAdminManager.GetPlayerById(integer) pulls from the DB, so I would think that, since changes are observed in playerAfter, that those changes were saved to the DB. However, when I reload the web page (which pulls from the DB), the old values are there.
Any ideas?
Here are some of the functions I mention:
Function GetPlayerById(ByVal Id As Integer) As DAL.Player
Return Container.Players.Where(Function(o) o.PlayerId = Id And o.IsVisible = True).SingleOrDefault
End Function
Sub SaveChanges()
Dim numberOfChanges As Integer = Container.SaveChanges()
Debug.WriteLine("No conflicts. " & numberOfChanges.ToString() & " updates saved.")
End Sub
EDIT
Container code:
Private _Container As DAL.LateralSportsContainer
Protected ReadOnly Property Container As DAL.LateralSportsContainer
Get
If _Container Is Nothing Then
Dim connStr As New System.Data.EntityClient.EntityConnectionStringBuilder
connStr.ProviderConnectionString = Web.Configuration.WebConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString
connStr.Metadata = "res://*/Lateral.csdl|res://*/Lateral.ssdl|res://*/Lateral.msl"
connStr.Provider = "System.Data.SqlClient"
_Container = New DAL.LateralSportsContainer(connStr.ConnectionString)
End If
Return _Container
End Get
End Property
Turns out I was using a non static (shared) Container. I had 2 Manager classes that both inherited from a BaseManager class were the Container was defined. I was executing the query command in one Manager and saving in another.
Doh!

Resources