How does one set a property of a JsonObject dynamically? - asp.net

I am using a method of passing Json to and from my markup using jquery and ajax. This can be described in more detail on this page: http://blogs.telerik.com/aspnet-ajax/posts/12-04-27/the-present-and-future-of-using-json-in-webforms.aspx
In this snippet of code, I try to set the object's value dynamically by setting a string variable named "test" to a business object's value:
Dim objOrder As Object = New JsonObject()
For Each Order As BoVendorOrder In Orders
Dim Vendor As New BoVendor(Order.VendorID)
Dim test As String = Order.VendorOrderID
objOrder.test = Vendor.VendorName + " - " + Order.VendorOrderPoNumber
Next
I left out some code for the sake of brevity. The goal is to get the objOrder.test to be equal to the VendorOrderID (a number in our SQL database) so that the JSON looks like this:
{
"123456": "VendorName - PONumber",
"678901": "VendorName - PONumber"
}
Any of you guys out there know how to do this?

Do you really need the order IDs to be properties of the object? It might be easier to just return a serialized Dictionary(Of String, String). You could still look up by order ID and it would be easier to loop over than the props of the Javascript object.
Here's an example of what you'd need to do using the dictionary approach:
Dim OrdersDict as New Dictionary(Of String, String)()
For Each Order as BoVendorOrder In Orders
If Not OrdersDict.ContainsKey(Order.VendorOrderID) Then
OrdersDict.Add(Order.VendorOrderID, Vendor.VendorName + " - " + Order.VendorOrderPoNumber)
End If
Next
' Serialize the dictionary object to JSON
' Using System.Web.Script.Serialization.JavascriptSerializer:
Dim Serializer As New JavaScriptSerializer
If MaxLength Then Serializer.MaxJsonLength = Int32.MaxValue
Dim x as String = Serializer.Serialize(OrdersDict) 'Return or response.write x as needed
'or
'Using JSON.net
Dim x as String = JsonConvert.SerializeObject(OrdersDict) 'Return or response.write x as needed

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.

combining two textbox values

i called a field from mysql into a readonly textarea and i made another textbox to allow users to add fields into the textarea. how do I combine the values from the textbox into the textarea?
an example of what i want to do is:
textarea
15/12: Nothing special today
16/12: another day
17/12: and so on
textbox
this is a new input
Result
15/12: Nothing special today
16/12: another day
17/12: and so on
18/12: this is a new input
The textarea is "log1" and the textbox is "txb1". I'm currently using
log = trim(request.form("log1"))
how do I do something like
log = trim(request.form("log1")) <br> date ": " trim(request.form("txb1"))
assuming date is a string variable, You would want to do the following:
log = trim(request.form("log1")) & "<br>" & [date] & ": " & trim(request.form("txb1"))
also, if date is a DateTime variable, you would want to use date.ToShortDateString() and instead of <br/> i would recommend using Environment.NewLine
and even better, you should use StringBuilder:
Dim SB As New StringBuilder()
SB.AppendLine(trim(request.form("log1")))
SB.AppendLine([date] & ": " & trim(request.form("txb1")))
log = SB.ToString()
UPDATE:
if you want to store the entire log in one record rather than a separate table, you better off saving it as a list of logs into a varbinary(MAX) column.
here is a full example of how to do it:
1. we start by creating a <div> element that will hold our pretty logs and will be handled by the server, and a text box for new logs:
<asp:TextBox ID="txb1" runat="server"></asp:TextBox>
<div id="Text_Div1" runat="server"></div>
2. now in the code behind, we create a class to hold 1 single line of log:
'create a log class and state that it serializable
<Serializable> _
Public Class MyLogRecord
Public Sub New(_msg As String)
[Date] = DateTime.Now
Message = _msg
End Sub
Public Property [Date]() As DateTime
Get
Return m_Date
End Get
Set
m_Date = Value
End Set
End Property
Private m_Date As DateTime
Public Property Message() As [String]
Get
Return m_Message
End Get
Set
m_Message = Value
End Set
End Property
Private m_Message As [String]
Public Function ToText() As String
Return [Date].ToShortDateString() & ": " & Convert.ToString(Message)
End Function
End Class
3. wherever you update the logs, whether its button_click or textbox_keydown, you do the following:
' create a list of logs
Dim MyLogs As List(Of MyLogRecord)
'check if we stored the logs already in the session,
'if yes, retrieve it from the session var,
'if not then create a new one.
If Session("MyLogs") IsNot Nothing Then
MyLogs = DirectCast(Session("MyLogs"), List(Of MyLogRecord))
Else
MyLogs = New List(Of MyLogRecord)()
End If
' create a new log record from the new textbox value
Dim _tempLog As New MyLogRecord(txb1.Text)
'add the new log to the list
MyLogs.Add(_tempLog)
'save it back in a session var:
Session("MyLogs") = MyLogs
4. in the part where you save the logs to the mysql db, you do it this way: first convert the list to a byte array and store it in a varbinary(MAX) column
'create a new binary formatter, include System.Runtime.Serialization.Formatters.Binary;
Dim formatter As New BinaryFormatter()
'create a byte array to store our logs list
Dim _logsBinary As Byte()
'create a memory stream to write the logs list into
Using _logStream As New MemoryStream()
'use the formatter to serialize the list in to an array of bytes
'directly into the memory stream
formatter.Serialize(_logStream, MyLogs)
'dump the memory stream into the byte array
_logsBinary = _logStream.ToArray()
End Using
' ... save the _logsBinary into mysql as a 'varbinary(max)' ...
5. in the place where you retrieve the logs from the mysql db, you de-serialize the byte array back to a logs list:
Dim MyLogs As New List(Of MyLogRecord)()
Dim formatter As New BinaryFormatter()
Using _logStream As New MemoryStream()
_logStream.Write(_logsBinary, 0, _logsBinary.Length)
_logStream.Position = 0
' de-serialize the byte array back into a logs list
MyLogs = DirectCast(formatter.Deserialize(_logStream), List(Of MyLogRecord))
End Using
6. in the place where you write the logs in your page, you do it this way:
Dim SB As New StringBuilder()
' create a temp date to compare against all the records,
' and initialize it with the first value or else you will have
' a orizontal line before the first row
Dim _prevDate As DateTime = MyLogs.First().[Date]
For Each _logRec As MyLogRecord In MyLogs
'take the date of the currently iterrated item and
'compare against the temp date, note that comparing months is not enough,
'month might be same/earlier but year can be higher
Dim _currentDate As DateTime = _logRec.[Date]
If _currentDate.Month > _prevDate.Month OrElse _currentDate.Year > _prevDate.Year Then
'append horizontal line
SB.AppendLine("<hr/>")
'update temp value
_prevDate = _currentDate
End If
'finally append the log: ToText() is the class custom
'function that we created above
SB.AppendLine(_logRec.ToText())
Next
'dump the logs into the server managed div:
Text_Div1.InnerHtml = SB.ToString()

VB.net Null reference on database connection

I know I'm being an idiot here and I just can't work it out. But i'm trying to take some data back from a vb.net database. It's falling over with a Object reference not set to an instance of an object error. And before the code runs it's saying the variable is being used before it's set, but I can't see how. Code:
Private taNotifications As dsDataTableAdapters.NotificationsTableAdapter = New dsDataTableAdapters.NotificationsTableAdapter
Dim notification As dsData.NotificationsDataTable = taNotifications.GetDataByClientID(userrow.UserID)
If notification.Rows.Count > 0 Then
Dim notificationrow As dsData.NotificationsRow
Dim forwardURL As String = notificationrow.ForwardLocation
End If
It falls over on the Dim forwardURL As String = notificationrow.ForwardLocation
The problem is that you have never instantiated the notificationRow inside the if statement. You've declared it, but it doesn't belong to anything. You need to make an assignment or loop through your rows before doing anything with this object:
Dim notificationrow As dsData.NotificationsRow ' this is not instantiated
Dim forwardURL As String = notificationrow.ForwardLocation
What you really want in this case is:
For Each notificationRow As dsData.NotificationRow In notification
Dim forwardURL As String = notificationRow.ForwardLocation
' Do Something
Next
If you only HAVE one row and you know you only have 1 or 0 rows then you could use your if statement by doing:
If notification.Rows.Count > 0 Then
Dim notificationrow As dsData.NotificationsRow = _
CType(notification.Rows(0), dsData.NotificationsRow)
Dim forwardURL As String = notificationrow.ForwardLocation
End If
Edit: In the code above, I originally just had notification.Rows(0). This will produce a DataRow object, but it will not be strongly typed. You need to perform the CType that I added in order to use the custom property ForwardLocation.
You never set notificationrow to anything. Did you mean to set it like this?
Dim notificationrow As dsData.NotificationsRow = CType(notification.Rows(0), dsData.NotificationsRow)

Getting the Request Variables from an ASP.NET page

I wrote the following function that works about 95% of the time, but I need it to work 100% (obviously):
Public Shared Function getPassedVars() As String
Const keyCount As Integer = 54 ' 54 seems to be the number of parameter keys passed by default (for this web_app).
' there are more if there is a form involved (ie. from search page)
Dim oParams As String = ""
Try
With HttpContext.Current
If .Request.Params.AllKeys.Count > keyCount Then
For i As Integer = 0 To (.Request.Params.AllKeys.Count - (keyCount + 1))
oParams &= String.Format("{0}={1}{2}", .Request.Params.Keys.Item(i), .Request.Params(i), IIf(i < .Request.Params.AllKeys.Count - (keyCount + 1), ";", ""))
Next
End If
End With
Return oParams
Catch ex As Exception
Return Nothing
End Try
End Function
It scrubs the Request.Params object for passed variables, which are in the beginning of the array (the remaining ones are ASP parameters). I am pretty sure I've seen a different way to get these parameters, but I haven't been able to figure it out. Any suggestions?
EDIT
So it looks like I can use the Request.URL.Query to achieve this, I will investigate this and post back.
Here is what I came up with:
Public Shared Function getPassedVars() As String
Dim oParams As String = ""
Dim qString As String = ""
Dim oSplit As New List(Of String)
Try
With HttpContext.Current
qString = .Request.Url.Query
If qString.Length > 0 Then 'do we have any passed variables?
If qString.StartsWith("?") Then qString = qString.Remove(0, 1) 'remove leading ? from querystring if it is there
oSplit.AddRange(qString.Split("&"))
For i As Integer = 0 To oSplit.Count - 1
oParams &= String.Format("{0}{1}", oSplit.Item(i), IIf(i < oSplit.Count - 1, ";", ""))
Next
Return oParams
Else
Return Nothing
End If
End With
Catch ex As Exception
Return Nothing
End Try
End Function
So far so good.
Request.QueryString is a NameValueCollection, so the easiest way to get the "parameters" is to do the following:
foreach (String s in Request.QueryString) {
Response.Write(s + " = " + Request.QueryString[s]);
}
Where is your function located? If it's executing in the page's code behind then you definitely do not need to use the HttpContext variable.
It looks like you are trying to get values from the query string.
For example, for this URL:-
http://www.tempuri.org/mypage.aspx?param1=x&param2=y
I assume you want retreive the values of the query string parameters param1 and param2?
If so, just use:-
Dim param1 as String = Request.QueryString("param1")
Otherwise, if these parameters are contained in a form (an HTTP POST request) then use the method which Mitchel Sellers suggests.
If you know the name you can use the following to get it by key value
Dim myParamValue as String = Request.Form("MyKeyName")
Otherwise, you can loop through the form collection, by key etc, to get the values. The key is, do you really need to be parsing all 54 items? Or are you simply looking for a few specific values?
httpcontext.Current.Request.QueryString("KeyName")
Request.Params will contain the query parameters you're after.
There's no need to parse the info from Request.URL since it's already done for you.

Resources