What is the best approach to send a Pushover via VBA?
In Pushover website code example, I didn't find a VBA example.
He is the Function.
PS: I use an auxiliar function to format strings
TesteFunction:
Public Sub Test()
Debug.Print PushOverPost("myApplication", "mySubscriptionGroup", "Hello Stackoverflow!")
End Sub
PushoverFunction:
' Send a post via PushOver
' #param In application as String: The application's token
' #param In group as String: The user/group token
' #param In message as String: The message that you want to send
' #return as String(): The post response
Public Function PushOverPost(ByVal application As String, ByVal group As String, ByVal message As String) As String
Dim xhttp As Object, params As String, url As String
Set xhttp = CreateObject("MSXML2.ServerXMLHTTP")
params = StringFormat("token={0}&user={1}&message={2}", application, group, message)
url = "https://api.pushover.net/1/messages.json"
With xhttp
.Open "POST", url, False
.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
.send params
PushOverPost = .responseText
End With
End Function
Auxiliar Function:
' Generate a string using .NET format, i.e. {0}, {1}, {2} ...
' #param In strValue as String: A composite format string that includes one or more format items
' #param In arrParames as Variant: Zero or more objects to format.
' #return as String: A copy of format in which the format items have been replaced by the string representations of the corresponding arguments.
' #example: Debug.Print StringFormat("My name is {0} {1}. Hey!", "Mauricio", "Arieira")
Public Function StringFormat(ByVal strValue As String, ParamArray arrParames() As Variant) As String
Dim i As Integer
For i = LBound(arrParames()) To UBound(arrParames())
strValue = Replace(strValue, "{" & CStr(i) & "}", CStr(arrParames(i)))
Next
StringFormat = strValue
End Function
Related
With assistance from outside sources I have this code that takes latitude and longitude and extracts zipcodes. Here is the code:
Public Function ReverseGeoCode(myInput1 As String, myInput2 As String) As String
'You will need to reference Microsoft XML, v6.0 object library
Dim XMLDoc As New DOMDocument60
Dim XMLNODE As IXMLDOMNode
Dim I As Long
Dim lat, lng, myAddress, myZipcode, reportZipcode As String
Dim splitAddress, splitZipcode As Variant
lat = myInput1
lng = myInput2
XMLDoc.Load "http://maps.googleapis.com/maps/api/geocode/xml?latlng=" & lat & "," & lng & " &sensor=false"
Do Until XMLDoc.readyState = 4
DoEvents
Loop
If Len(XMLDoc.Text) = 0 Then
Call MsgBox("No Data!")
Exit Function
End If
Set XMLNode = XMLDoc.SelectSingleNode("/GeocodeResponse/result/formatted_address")
For i= 0 To XMLNode.ChildNodes.Length - 1
myAddress = XMLNode.ChildNodes(i).Text
Next i
splitAddress = Split(myAddress, ",")
myZipcode = splitAddress(2)
myZipcode = Trim(myZipcode)
splitZipcode = Split(myZipcode, " ")
reportZipcode = splitZipcode(1)
reportZipcode = Trim(reportZipcode)
ReverseGeoCode = reportZipcode
End Function
So the code works, and I know it might not be the cleanest. But the issue is when I call it in the Excel sheet using "=ReverseGeoCode(Cell1, Cell2)". Sometimes it works fine, other times it produces the return "#VALUE!" and I am not entirely sure why. I attached an image below to show you an example of the error. Does anyone have an idea of why this error is producing?
General observations:
So to pick up on what I wrote in the comments, here is an outline.
You don't want to use an User Defined Function. This will keep on making repeated calls. You definitely risk hitting a call limit to the API without an API key, and possibly with; it is inefficient and it is not necessary. Instead, write a sub which you call once and which loops all the required cells in the sheet and issues the API calls and returns the zip codes. An API key is a method of authentication used with many API calls. You shouldn't share it by the way.
These repeated calls, possibly hitting a limit and the fact that UDFs are frequently calculated maybe the source of your woes.
With efficiency in mind, first remove duplicates from the sheet to avoid calls that are not required. Switch of Screen-Updating and anything else e.g. CalculationMode to manual whilst performing.
From what I have read you require an API key once you have hit a daily limit. Not sure what the API limit is for free version or without API key.
Outline code (XML request with some psuedo code):
Option Explicit
Public Sub ListZipCodes()
Dim lat As Double, longitude As Double
Const APIKEY As String = "yourAPIkey"
Application.ScreenUpdating = False '<==Speed up code when actually working with sheet
'Code to remove duplicates
'Code to loop sheet and call function on each input set of values
'Example call. These would be picked up from cells
lat = 40.714224
longitude = -73.961452
Debug.Print GetZipCode(lat, longitude, APIKEY)
Application.ScreenUpdating = True
End Sub
Public Function GetZipCode(ByVal lat As Double, ByVal longitude As Double, ByVal APIKEY As String) As String
Dim sResponse As String
With CreateObject("MSXML2.XMLHTTP")
Dim URL As String
URL = "https://maps.googleapis.com/maps/api/geocode/xml?latlng=" & lat & "," & longitude & "&key=" & APIKEY
.Open "GET", URL, False
.send
If .Status <> 200 Then
GetZipCode = "API call failed"
Exit Function
End If
Dim XMLDoc As New DOMDocument60, XMLNODE As IXMLDOMNode
XMLDoc.Load .responseBody
If Len(XMLDoc.Text) = 0 Then GetZipCode = "No data"
Set XMLNODE = XMLDoc.SelectSingleNode("/GeocodeResponse/result/formatted_address")
GetZipCode = Split(Trim$(Split(XMLNODE.Text, Chr$(44))(2)), Chr$(32))(1)
End With
End Function
Requesting JSON rather than XML response:
The reason calling as JSON was falling over was that the response needed to be decoded. Here is the function re-written to handle a JSON response.
This requires the download of JSONConverter, which you then import and add a reference to Microsoft Scripting Runtime via VBE > Tools > References.
The example below was run with
latitude: 42.9865913391113,
longitude: -100.137954711914
VBA:
Public Function GetZipCode(ByVal lat As Double, ByVal longitude As Double, ByVal APIKEY As String) As String
Dim sResponse As String, json As Object
With CreateObject("MSXML2.XMLHTTP")
Dim URL As String, formattedAddress As String
URL = "https://maps.googleapis.com/maps/api/geocode/json?latlng=" & lat & "," & longitude & "&key=" & APIKEY
.Open "GET", URL, False
.send
If .Status <> 200 Then
GetZipCode = "API call failed"
Exit Function
End If
Set json = JsonConverter.ParseJson(StrConv(.responseBody, vbUnicode))
formattedAddress = json("results").item(1)("formatted_address")
GetZipCode = Split(Trim$(Split(formattedAddress, Chr$(44))(2)), Chr$(32))(1)
End With
End Function
With a JSON request the initial object you get back is a dictionary, as denoted by the opening "{" in the decoded response:
i.e. Set json = JsonConverter.ParseJson(StrConv(.responseBody, vbUnicode)) returns a dictionary object
The data of interest, in the dictionary, has the key "results", as you may observe from the above.
This can be accessed with json("results"), which returns a collection of dictionaries. This being denoted by the following "[", for collection, and subsequently by the start of the first dictionary within the collection, indicated again by "{".
I can grab the first dictionary in the collection by index with:
json("results").item(1)
An inspection of the keys in this dictionary shows that one of the keys is what we are after i.e."formatted_address".
It's associated value is a primitive datatype; in this case a string. This means we can directly access it using the key (a further object is not returned).
formattedAddress = json("results").item(1)("formatted_address")
Now that we have the address string, we can parse it as we did before:
GetZipCode = Split(Trim$(Split(formattedAddress, Chr$(44))(2)), Chr$(32))(1)
End note:
You can use Postman, amongst other tools, to test API calls, and in this case inspect the JSON response. Indeed, to see what kind of response you are getting full stop.
Help:
It is very quick and easy to set up a project, generate an API key and get started. Maybe 10 minutes to read through and perform.
Instructions on setting up a project and getting an API key
Enabling the API
Understanding how to make API calls to the Geocoding API
I am trying to write simple application for myself and when i try to call
getInfo method i always get a error into the response. Key, sign, method or nonce is incorrect. I found a number of examples but i still can't find mistake in my code. Could anyone help me with it?
The code works fine for hitbtc. I know yobit is a bit different but I think I have accomodate that.
My code:
Protected Shared Function readStrings(signatureheader As String, host As String, pathandQuery As String, post As String, secret As String, hasher As System.Security.Cryptography.HMAC, otherHeaders As Tuple(Of String, String)()) As String
'apikey=98998BEEB8796455044F02E4864984F4
'secret=44b7659167ffc38bb34fa35b5c816cf5
hasher.Key = exchanges.getBytes(secret)
Dim url = host + pathandQuery ' url = "https://yobit.net/tapi/"
Dim wc = New CookieAwareWebClient()
Dim sigHash2 = ""
If post = "" Then
sigHash2 = CalculateSignature2(pathandQuery, hasher)
Else
'post = "method=getInfo&nonce=636431012620"
sigHash2 = CalculateSignature2(post, hasher) 'sighash2= "ece0a3c4af0c68dedb1f840d0aef0fd5fb9fc5e808105c4e6590aa39f4643679af5da52b97d595cd2277642eb27b8a357793082007abe1a3bab8de8df24f80d2"
End If
wc.Headers.Add(signatureheader, sigHash2) ' SignatureHeader ="Sign"
Dim response = ""
For Each oh In otherHeaders ' otherHeaders =(0) {(Key, 98998BEEB8796455044F02E4864984F4)} System.Tuple(Of String, String)
wc.Headers.Add(oh.Item1, oh.Item2)
Next
'- wc.Headers {Sign: ece0a3c4af0c68dedb1f840d0aef0fd5fb9fc5e808105c4e6590aa39f4643679af5da52b97d595cd2277642eb27b8a357793082007abe1a3bab8de8df24f80d2 Key: 98998BEEB8796455044F02E4864984F4 } System.Net.WebHeaderCollection
'url = "https://yobit.net/tapi/"
'post = "method=getInfo&nonce=636431012620"
If post = "" Then
response = wc.DownloadString(url)
Else
response = wc.UploadString(url, post) 'response = response "{"success":0,"error":"invalid key, sign, method or nonce"}" String
End If
Return response
End Function
The code has been tested succesfully for hitbtc.
So the crypto part is correct. I put it here anyway for completeness
Protected Shared Function CalculateSignature2(text As String, hasher As System.Security.Cryptography.HMAC) As String
Dim siginhash = hasher.ComputeHash(exchanges.getBytes(text))
Dim sighash = exchanges.getString(siginhash)
Return sighash
End Function
So,
for sanity check
This code works
Public Overrides Sub readbalances()
Dim response = readStrings("X-Signature", "https://api.hitbtc.com", "/api/1/trading/balance?nonce=" + exchanges.getNonce().ToString + "&apikey=" + _apiKey, "", _secret, New System.Security.Cryptography.HMACSHA512(), {})
End Sub
With yobit things are different. I got to use post instead of get. I got to add more headers. However, I think I have fixed that.
It doesn't work.
The python function for yobit API is this I just need to translate that to vb.net which I think I have done faithfully
API Call Authentication in Python ( Working PHP example )
I think the mistake is around here
request_url = "https://yobit.net/tapi";
request_body = "method=TradeHistory&pair=ltc_btc&nonce=123";
signature = hmac_sha512(request_body,yobit_secret);
http_headers = {
"Content-Type":"application/x-www-form-urlencoded",
"Key":yobit_public_key,
"Sign":signature
}
response = http_post_request(request_url,request_body,http_headers);
result = json_decode(response.text);
There the stuff that I copied is method=getInfo&nonce=636431012620 which is what I put in post.
So that seems right.
Looks like it works.
I just need to change the nonce so that it's between 0 to 2^31
So this is the error
post = "method=getInfo&nonce=636431012620
The nonce shouldn't be that big. At most it should be
2147483646
Also though not documented, I must add
content type as one of the header. This is the final solution
Dim nonce = exchanges.getNonce().ToString
Dim content = hashObject("", nonce, "method=getInfo&nonce=")
Dim sighash = computeSig(content)
Dim result = CookieAwareWebClient.downloadString1("https://yobit.net/tapi/", content, {New Tuple(Of String, String)("Key", _apiKey), New Tuple(Of String, String)("Sign", sighash), New Tuple(Of String, String)("Content-Type", "application/x-www-form-urlencoded")})
So I added New Tuple(Of String, String)("Content-Type", "application/x-www-form-urlencoded") as one of the headers
Protected Overridable Function computeSig(content As String) As String
Dim hasher = New System.Security.Cryptography.HMACSHA512(System.Text.Encoding.UTF8.GetBytes(_secret))
Return CalculateSignature2(content, hasher)
End Function
Public Shared Function CalculateSignature2(content As String, hasher As System.Security.Cryptography.HMAC) As String
Dim siginhash = hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes(content))
Dim sighash = exchanges.getString(siginhash) 'convert bytes to string
Return sighash
End Function
Public Shared Function downloadString1(url As String, post As String, otherHeaders As Tuple(Of String, String)()) As String
Dim wc = New CookieAwareWebClient()
For Each oh In otherHeaders
wc.Headers.Add(oh.Item1, oh.Item2)
Next
Dim response = String.Empty
Try
If post = "" Then
response = wc.DownloadString(url)
Else
response = wc.UploadString(url, post)
End If
Catch ex As Exception
Dim a = 1
End Try
Return response
End Function
How can my VB6 form POST 2 vars, pull the results from a URL and then assign a VB6 var to the results?
I need someone to show me VERY basic VB6 sample code or point me in the right direction. This is the simplest form - in the final product, the PHP vars will write to MySQL, but that's not what i need help with.
I have a simple PHP page that accepts 2 parameters:
test.php?var1=secret&var2=pass
Here's my really simple PHP code
<?php
$var1 = $_GET['var1'];
$var2 = $_GET['var2'];
$varAcc = "ACCEPTED";
$varDen = "DENIED";
if ($var1 === "secret" && $var2 === "pass")
{
echo $varAcc;
}
else
{
echo $varDen;
}
?>
The logic behind this is gonna be VB6 login with "userName", "passWord" and "hardWareID", and send a hash. The hash will be checked against MySQL to see whether it exists, and returns YES or NO for access, how many days left on their account, and some other details, like FULL NAME, ACCOUNT INFO, etc.
( NO.. I do not want to use XML, just thought i would put that out there.. Just POST & Receive to vars)
Thank You...
VB forms don't have any built-in mechanism for sending HTTP requests. Some may suggest you use the Internet Transfer Control. However, the VB UserControl has a mechanism for HTTP that you can use without the need for third party controls, assuming you use the GET method, and use the query string to pass your parameters. If you have to use POST, you must use the Internet Transfer Control.
Create a VB project with a reference to "Microsoft Scripting Runtime" (see the menu Project=>References). Add a UserControl. Call it "HttpService". Set InvisibleAtRuntime=True. Add the following code to the UserControl:
Option Explicit
Private Const m_ksProperty_Default As String = ""
Private m_sHost As String
Private m_nPort As Long
Private m_sPath As String
Private m_dctQueryStringParameters As Scripting.Dictionary
Private m_sOutput As String
' Ensure that all parts of the query string are deleted.
Public Sub ClearQueryString()
Set m_dctQueryStringParameters = New Scripting.Dictionary
End Sub
' Executes "GET" method for URL.
Public Function Get_() As String
' Read in data from URL. UserControl_AsyncReadComplete will fire when finished.
UserControl.AsyncRead "http://" & m_sHost & ":" & CStr(m_nPort) & "" & m_sPath & "?" & GetQueryString(), vbAsyncTypeByteArray, m_ksProperty_Default, vbAsyncReadSynchronousDownload
' Return the contents of the buffer.
Get_ = m_sOutput
' Clear down state.
m_sOutput = vbNullString
End Function
' Returns query string based on dictionary.
Private Function GetQueryString() As String
Dim vName As Variant
Dim sQueryString As String
For Each vName In m_dctQueryStringParameters
sQueryString = sQueryString & CStr(vName) & "=" & m_dctQueryStringParameters.Item(vName) & "&"
Next vName
GetQueryString = Left$(sQueryString, Len(sQueryString) - 1)
End Function
' Sets the remote host.
Public Property Let Host(ByVal the_sValue As String)
m_sHost = the_sValue
End Property
' Sets the directory and filename part of the URL.
Public Property Let Path(ByVal the_sValue As String)
m_sPath = the_sValue
End Property
' Sets the port number for this request.
Public Property Let Port(ByVal the_nValue As Long)
m_nPort = the_nValue
End Property
' Sets a name/value pair in the query string. Supports duplicate names.
Public Property Let QueryStringParameter(ByVal the_sName As String, ByVal the_sValue As String)
m_dctQueryStringParameters.Item(the_sName) = the_sValue
End Property
' Fired when the download is complete.
Private Sub UserControl_AsyncReadComplete(AsyncProp As AsyncProperty)
' Gets the data from the internet transfer.
m_sOutput = StrConv(AsyncProp.Value, vbUnicode)
End Sub
Private Sub UserControl_Initialize()
' Initialises the scripting dictionary.
Set m_dctQueryStringParameters = New Scripting.Dictionary
End Sub
To use this UserControl, add it to your form. Call it "HttpService". Add a TextBox called "txtOutput" to test the following code on the form:
HttpService.Host = "localhost"
HttpService.Port = 80
HttpService.Path = "/test.php"
HttpService.QueryStringParameter("var1") = "secret"
HttpService.QueryStringParameter("var2") = "pass"
txtOutput.Text = HttpService.Get_
If you must use POST, then you will have to use the Internet Transfer Control. In the VB6 IDE, press CTL-T, and select "Microsoft Internet Transfer Control 6.0". Press Ok.
Add an instance of the control to the form. Call it "Inet". Add a CommandButton called "cmdPost" to the form. Add a reference to "Microsoft Scripting Runtime" (see the menu Project=>References).
Add the following code to your form:
Option Explicit
Private Declare Function InternetCanonicalizeUrl Lib "Wininet.dll" Alias "InternetCanonicalizeUrlW" ( _
ByVal lpszUrl As Long, _
ByVal lpszBuffer As Long, _
ByRef lpdwBufferLength As Long, _
ByVal dwFlags As Long _
) As Long
Private m_sData As String
Private m_nDataReceived As Long
Private m_bPostActive As Boolean
Private m_bDataReceived As Boolean
Private m_bError As Boolean ' For error handling.
Private m_bDisconnected As Boolean
Private Sub cmdPost_Click()
Dim dctParameters As Scripting.Dictionary
txtOutput.Text = vbNullString
m_sData = vbNullString
Set dctParameters = New Scripting.Dictionary
dctParameters.Add "var1", "secret"
dctParameters.Add "var2", "pass"
txtOutput.Text = Post("http://localhost:80/test.php", dctParameters)
End Sub
' Returns post data string based on dictionary.
Private Function GetPostDataString(ByRef the_dctParameters As Scripting.Dictionary) As String
Dim vName As Variant
Dim sPostDataString As String
For Each vName In the_dctParameters
sPostDataString = sPostDataString & UrlEncode(CStr(vName)) & "=" & UrlEncode(CStr(the_dctParameters.Item(vName))) & "&"
Next vName
GetPostDataString = Left$(sPostDataString, Len(sPostDataString) - 1)
End Function
Private Sub Inet_StateChanged(ByVal State As Integer)
' Ignore state change if we are outside the Post function.
If m_bPostActive Then
Select Case State
Case StateConstants.icResponseReceived
ReceiveData False
Case StateConstants.icResponseCompleted
ReceiveData True
Case StateConstants.icDisconnected
m_bDisconnected = True
Case StateConstants.icError
m_bError = True
End Select
End If
End Sub
' Synchronous Post function.
Private Function Post(ByRef the_sURL As String, ByRef the_dctParameters As Scripting.Dictionary)
Dim sPostData As String
Dim sHeaders As String
' Flag that we are in the middle of this function.
m_bPostActive = True
' Create a string containing the POST parameters.
sPostData = GetPostDataString(the_dctParameters)
' Create a headers string to allow POST.
sHeaders = _
"Content-Type: application/x-www-form-urlencoded" & vbNewLine & _
"Content-Length: " & CStr(Len(sPostData)) & vbNewLine & _
"Connection: Keep-Alive" & vbNewLine & _
"Cache-Control: no-cache" & vbNewLine
Inet.Execute the_sURL, "POST", GetPostDataString(the_dctParameters), sHeaders
' Allow Inet events to fire.
Do
DoEvents
Loop Until m_bDataReceived Or m_bDisconnected
If m_bDataReceived Then
Post = m_sData
End If
' Clear all state flags to defaults.
m_bDataReceived = False
m_bDisconnected = False
m_bError = False
m_sData = vbNullString
m_nDataReceived = 0
' Flag that we have exited this function.
m_bPostActive = False
End Function
' Receive as much data as we can.
' <the_bCompleted> should be True if the response is completed i.e. all data is available.
Private Sub ReceiveData(ByVal the_bCompleted As Boolean)
Const knBufferSize As Long = 1024
Dim nContentLength As Long
Dim sContentType As String
Dim sChunk As String
Dim nChunkSize As Long
' If we haven't yet created our buffer, do so now, based on the size of the incoming data.
If m_nDataReceived = 0 Then
nContentLength = CLng(Inet.GetHeader("Content-length"))
m_sData = Space$(nContentLength)
' You might want to do a check on the content type here, and if it is wrong, cancel the request with Inet.Cancel .
sContentType = Inet.GetHeader("Content-type")
End If
' Retrieve data until we have all the data.
Do Until m_nDataReceived = Len(m_sData)
' If called when not all data has been received, then exit function if it is currently executing.
If Not the_bCompleted Then
If Inet.StillExecuting Then
Debug.Print "Exiting"
Exit Sub
End If
End If
' Get a chunk, copy it into the output buffer, and increment the amount of data received.
sChunk = Inet.GetChunk(knBufferSize, DataTypeConstants.icString)
nChunkSize = Len(sChunk)
Mid$(m_sData, m_nDataReceived + 1, nChunkSize) = sChunk
m_nDataReceived = m_nDataReceived + nChunkSize
Loop
' Flag that all data has been retrieved.
m_bDataReceived = True
End Sub
' Encode the URL data.
Private Function UrlEncode(ByVal the_sURLData As String) As String
Dim nBufferLen As Long
Dim sBuffer As String
' Only exception - encode spaces as "+".
the_sURLData = Replace$(the_sURLData, " ", "+")
' Try to #-encode the string.
' Reserve a buffer. Maximum size is 3 chars for every 1 char in the input string.
nBufferLen = Len(the_sURLData) * 3
sBuffer = Space$(nBufferLen)
If InternetCanonicalizeUrl(StrPtr(the_sURLData), StrPtr(sBuffer), nBufferLen, 0&) Then
UrlEncode = Left$(sBuffer, nBufferLen)
Else
UrlEncode = the_sURLData
End If
End Function
I can't seem to work out how to get a value from my string using VB.net
If I have a string in my textbox that says:
WWW-Authenticate: Digest realm="MyServer",qop="auth",algorithm="MD5",maxbuf=1000,nonce="3b010c090c0a0000c0a80157c7007f03c5",opaque="4e6573732041636365737320436f6e74"
How can I get each of the values after the = in the string.
I have tried using
Dim s = "WWW-Authenticate: Digest realm='MyServer',qop='auth',algorithm='MD5',maxbuf=1000,nonce='3b010c090c0a0000c0a80157c7007f03c5',opaque='4e6573732041636365737320436f6e74'"
Dim pattern = "="
Dim matches = Regex.Matches(s, pattern)
Dim values = matches.OfType(Of Match).Select(Function(m) m.Value)
For Each v In values
MsgBox(v)
Next
But it only returns the = in the messagebox.
I want to be able to get just the part after the = sign.
Anyone able to help?
I have tried using the following but it still includes the realm= qop= etc.. in the string. (but includes it at the end of the next item.
Dim s = "WWW-Authenticate: Digest realm='Ness Access Control',qop='auth',algorithm='MD5',maxbuf=1000,nonce='3b010c090c0a0000c0a80157c7007f03c5',opaque='4e6573732041636365737320436f6e74'"
Dim result_array As Array = Split(s, "=", 6)
For Each v In result_array
MsgBox(v)
Next
Regular Expressions!
Imports System.Text.RegularExpressions
Module Module1
Sub Main()
Dim s As String = "WWW-Authenticate: Digest realm='MyServer',qop='auth',algorithm='MD5',maxbuf=1000,nonce='3b010c090c0a0000c0a80157c7007f03c5',opaque='4e6573732041636365737320436f6e74'"
'Regular Expression, matches word before equals, and word after equals
Dim r As New Regex("(\w+)\='([^']+)'")
'All the matches!
Dim matches As MatchCollection = r.Matches(s)
For Each m As Match In matches
'm.Groups(1) = realm, qop, algorithm...
'm.Groups(2) = MyServer, auth, MD5...
Console.WriteLine(m.Groups(2))
Next
Console.ReadLine()
End Sub
End Module
And if you want everything in a nice key-value dictionary:
Dim dict As New Dictionary(Of String, String)
For Each m As Match In matches
'm.Groups(1) = realm, qop, algorithm...
'm.Groups(2) = MyServer, auth, MD5...
dict(m.Groups(1).ToString()) = dict(m.Groups(2).ToString())
Next
A case for a specific string extension.
How to transform a specific formatted string in a Dictionary with keys and values
Public Module StringModuleExtensions
<Extension()>
Public Function ToStringDictionary(ByVal str as String, _
ByVal OuterSeparator as Char, _
ByVal NameValueSeparator as Char) _
As Dictionary(of String, String)
Dim dicText = New Dictionary(Of String, String)()
if Not String.IsNullOrEmpty(str) then
Dim arrStrings() = str.TrimEnd(OuterSeparator).Split(OuterSeparator)
For Each s in arrStrings
Dim posSep = s.IndexOf(NameValueSeparator)
Dim name = s.Substring(0, posSep)
Dim value = s.Substring(posSep + 1)
dicText.Add(name, value)
Next
End If
return dicText
End Function
End Module
Call with
Dim test = "WWW-Authenticate: Digest realm=""MyServer"",qop=""auth"",algorithm=""MD5"", maxbuf=1000,nonce=""3b010c090c0a0000c0a80157c7007f03c5"",opaque=""4e6573732041636365737320436f6e74"""
Dim dict = test.ToStringDictionary(","c, "="c)
For Each s in dict.Keys
Console.WriteLine(dict(s))
Next
(probably you need to remove the WWW-Authenticate line before.
You are looking for the split() function.
Dim logArray() As String
logArray = Split(s, "=")
For count = 0 To logArr.Length - 1
MsgBox(logArray(count))
Next
I have this url that i need to decode:
http://gistest:54321/default.aspx?data=%7B%22id%22:%2269403%22,%22longitude%22:%22-143.406417%22,%22latitude%22:%2232.785834%22,%22timestamp%22:%2223-10%2010:12%22%7D
This code changes every time
I use this code:
<%Response.Write(Request.QueryString.Item("data") )%><br/>
<%Response.Write(Request.QueryString.Item("id") )%><br/>
<%Response.Write(Request.QueryString.Item("longitude") )%><br/>
<%Response.Write(Request.QueryString.Item("latitude") )%><br/>
<%Response.Write(Request.QueryString.Item("timestamp") )%><br/>
But i only get this as output, maybe there is an option where to check if data is not null, and then i request.querystring the other parts in data:
{"id"="69403","longitude"="-143.406417","latitude"="32.785834","timestamp"="23-10 10:12"}
This is from
<%Response.Write(Request.QueryString.Item("data") )%>
I really hope I understood the problem correctly. I am assuming you require the values of each key within the query string key called Data? To do so I used the code below:
Dim values() As String = Server.UrlDecode(Request.QueryString("data")).Replace("{", "").Replace("}", "").Split(New Char() {","}, StringSplitOptions.RemoveEmptyEntries)
For Each value As String In values
Dim keyValue() As String = value.Split(New Char() {":"}, StringSplitOptions.RemoveEmptyEntries)
Response.Write(keyValue(0).Replace("""", "") & " : " & keyValue(1).Replace("""", "") & "<br/>")
Next
In a nutshell, I decode the QueryString("data"), replace the braces and split the string into an array by using the comma as the first split character. We then end up with an array containing values in the following format "id":"649403".
Thereafter I iterate through the values and split one final time for each value based on the semi-colon (:) character.
With this method you can build and manipulate the data dynamically.
Code Edit
I replaced all references of ":" with "=" to ensure that the time stamp will be correctly retrieved and then split the key values based on =. You can use a select case to assign variables to values if necessary. (Obviously make sure your variable is not declared within the select as it will not be in the right scope for later use!)
If Request.QueryString("data") IsNot Nothing Then
Dim values() As String = Request.QueryString("data").Replace("{", "").Replace("}", "").Replace(""":""", """=""").Split(New Char() {","}, StringSplitOptions.RemoveEmptyEntries)
For Each value As String In values
Dim keyValue() As String = value.Split(New Char() {"="}, StringSplitOptions.RemoveEmptyEntries)
Response.Write(keyValue(0).Replace("""", "") & " : " & keyValue(1).Replace("""", "") & "<br/>")
Select Case keyValue(0).ToLower()
Case "id"
Dim id As String = keyValue(1)
End Select
Next
End If
Reflection Edit
Create an instance of your object then retrieve all its properties (Dim properties() As PropertyInfo = myObj.GetType().GetProperties()). Iterate through the properties and set the value where the name is equal to the key. Don't forget to import the System.Reflection library.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim data As String = "%7B%22id%22:%2269403%22,%22longitude%22:%22-143.406417%22,%22latitude%22:%2232.785834%22,%22timestamp%22:%2223-10%2010:12%22%7D"
If data IsNot Nothing Then
Dim myObj As New MyObject
Dim properties() As PropertyInfo = myObj.GetType().GetProperties()
Dim values() As String = Server.UrlDecode(data).Replace("{", "").Replace("}", "").Replace(""":""", """=""").Split(New Char() {","}, StringSplitOptions.RemoveEmptyEntries)
For Each value As String In values
Dim keyValue() As String = value.Split(New Char() {"="}, StringSplitOptions.RemoveEmptyEntries)
For Each prop As PropertyInfo In properties
If prop.Name.ToLower = keyValue(0).ToLower.Replace("""", "") Then
prop.SetValue(myObj, keyValue(1), Nothing)
End If
Next
Next
myObj.Save()
End If
End Sub
Public Class MyObject
Private _ID As String
Private _Longitude As String
Private _Latitude As String
Private _Timestamp As String
Public Property ID As String
Get
Return _ID
End Get
Set(value As String)
_ID = value
End Set
End Property
Public Property Longitude As String
Get
Return _Longitude
End Get
Set(value As String)
_Longitude = value
End Set
End Property
Public Property Latitude As String
Get
Return _Latitude
End Get
Set(value As String)
_Latitude = value
End Set
End Property
Public Property Timestamp As String
Get
Return _Timestamp
End Get
Set(value As String)
_Timestamp = value
End Set
End Property
Public Sub Save()
'Save logic here
End Sub
End Class
I think the problem you are running into is that there only is one querystring parameter in the URL you posted, and that is data. The rest of the information is encoded in the data querystring value. The value stored in data almost looks like a JSON/Javascript object, except with an = in between the property names and values instead of a :.
So, basically you won't be able to use Request.QueryString to get the values of id, longitude, latitude, etc. I think your options are to either write some code to parse the value of data yourself or replace the = with : and use a JSON parser for .NET (i.e., the JavascriptSerializer class or JSON.net).
Personally, I would write a method in the codebehind that would return a Dictionary(Of String, Object). In that method just I would just change every "=" to a ":" and then use the JavaScriptSerializer provided with .NET to parse the string. I don't have an ASP.NET instance handy right now, but the following sample I threw together in LinqPad should illustrate the idea:
Sub Main
Dim url = "http://gistest:54321/default.aspx?data=%7B%22id%22=%2269403%22,%22longitude%22=%22-143.406417%22,%22latitude%22=%2232.785834%22,%22timestamp%22=%2223-10%2010:12%22%7D"
Dim uri = New Uri(url)
Dim data = System.Web.HttpUtility.ParseQueryString(uri.Query)("data")
Dim o = ParseData(data)
Console.WriteLine(o("id"))
Console.WriteLine(o("longitude"))
Console.WriteLine(o("latitude"))
Console.WriteLine(o("timestamp"))
End Sub
Function ParseData(data As String) As Dictionary(Of String, Object)
Dim js = new System.Web.Script.Serialization.JavaScriptSerializer()
Dim o = js.DeserializeObject(data.Replace("""=""", """:"""))
ParseData = DirectCast(o, Dictionary(Of String, Object))
End Function
One thing to note about this approach is that I am expecting the url to be in the same format as what you posted. You may need to modify this method to make it more robust to handle different inputs.
If you drop the ParseData function into your codebehind, then something like the following code in your front page should give you the output you are looking for (again, sorry I don't have an ASP.NET instance to test with right now):
<%
Dim o = ParseData(Request.QueryString.Item("data"))
Response.Write(o("id"))
Response.Write("<br />")
Response.Write(o("longitude"))
Response.Write("<br />")
Response.Write(o("latitude"))
Response.Write("<br />")
Response.Write(o("timestamp"))
Response.Write("<br />")
%>