I have a unique need that I cannot figure out for myself. I am first saving the data I want to send to the web service db to a db table locally. When I push the data to the web service db, I want to delete the records from the local table as they are successfully added.
This is for a desktop app that can be used offline. If the user is offline, I want the data to remain in the temp table and not get deleted. Once they are connected, the app will try the Send method again, and if successful, will delete the records as they are added
Here is the code for this process. Could anyone share how I can accomplish this? This is deleting from the temp table, even when I disconnect from the net
'first save to temp table
dbUser.ExecuteSQL("INSERT INTO XCTempTable (X, Y, Z) VALUES (?, ?, ?)", "X", "Y", "Z")
'get tempID from newly added to delete this one once uploaded
dim sql as String = "SELECT id FROM XCTempTable ORDER BY id DESC"
dim rs as RowSet = dbUser.SelectSQL(sql)
'set property for deleting later
dim tempID as String = rs.Column("id").StringValue
dim bCanDelete as Boolean
'add to server. if successful, will delete below
try
dim Socket As New SimpleHTTP.SynchronousHTTPSocket
Socket.RequestHeader("Cache-Control") = "no-cache"
Socket.RequestHeader("Connection") = "close"
dim jCode As New JSONItem
jCode.Value("XXXX") = "XXXX"
jCode.Value("XXXX") = "XXXX"
jCode.Value("XXXX") = "XXXX"
dim data as String = jCode.ToString.DefineEncoding(Encodings.UTF8)
Socket.SetRequestContent(data, "application/json")
Socket.Send("POST", "https://XXXX.xojocloud.net/XXXX")
'post added so set to delete
bCanDelete = true
catch e as NetworkException
bCanDelete = False
Return
end try
if bCanDelete = true then
dbUser.ExecuteSQL("DELETE FROM XCTempTable WHERE id = '" + tempID + "'")
end if
/// I don't think the bCanDelete property is working since it is always deleting from the temp table, even when not connected to the internet
Is there a " HeadersReceived" event or other event following a POST that you could evaluate? That seems like a better place to put the bCanDelete bool and call any subsequent operations.
There wasnât in the class originally, so i added it. Unfortunately, that didnât seem to work. Not sure if I needed to add anything else to HeadersReceived, but I just did
bCanDelete = True
Assuming if it was received, this can be set to true. Also, and not sure if this matters, but this class is not part of the window where the POST call is made. There was an example project (couldnât find it at the moment), but that project also did not include the class on the window, so I did not do this either
Iâll assume that the HeadersReceived will fire as would other related events, but you should be evaluating the HTTPStatus that is passed in to evaluate if it is â200â (aka âOKâ) or any of the many many other codes that indicate an error. You would likely only set bCanDelete to true on â200â, otherwise handle the other response codes accordingly.
HeadersReceived (URL As String, HTTPStatus As Integer)
Offline sync is not a unique need Nevertheless it isnât easy to achieve. I am currently working on a similar functionality.
Note: The only part that is âsynchronousâ in that class is if you are calling Socket.Send from a Thread. The thread will be paused until the HTTPSocket has received something in the ContentReceived event or the Error event.
If you use Socket.Send on the Main thread, your code will continue execution before the socket got a response.
I had a look at the SynchronousHTTPSocket class and found some errors in your code.
If your code is not running from a Thread, bCandDelete will alway be true in the code you wrote. Thatâs because it isnât waiting for the result of Socket.Send
You will either need to call that code from a Thread, then check the HTTPStatus code and response:
Var response As String = Socket.LastContent
If Socket.LastHTTPStatus = 200 Then //And check response if relevant
bCanDelete = True
End if
This, I believe, is my problem. This window is calling .Send directly and not using a thread. I will give this a try tomorrow. For some reason, I thought of only needing to use a thread when wanting to post data from a loop that might take a while. Since this example was only posting one item, I didnât think it necessary to use a thread. Thanks for this!
Also wasnât aware of this! This will make it easier to grab the ID I need
Will post back tomorrow if I run into any further issues, but I think this gets me on track
Also that class doesnât have a ton of utility anymore. URLConnection has a built-in SendSync method now. And you can call it from the main thread, though I strongly suggest you donât.
But I guess you donât need it there. Your design seems flawed for the purpose you said.
You should design a flow (in a piece of paper?) before writing the code.
Looks like you want 2 separated repeating asynchronous tasks running in parallel:
Task 1: // Send something to the remote db
Insert the record in the "output queue" db // done
End task 1
Task 2: // dump the queue to the remote endpoint
Do we have something in the output queue?
yes: get the oldest record (and its id)
upload it
success?
yes: delete it from the output queue
no: continue. maybe sleep a bit
no: continue, sleep a bit, longer than when actively dumping content
End task 2
Adding the Send call and doing all the work in the thread did the trick. Thank you all for teaching me once again. Very much appreciated! Happy holidays!
I think this was your class and example project I found on the forum Thom, yes? Iâve found it to be very helpful. Not sure what you mean by not having a lot of utility. I think it works great. There will be some instances where Iâll use the URLConnection.Send, but Iâll be using your class for other parts. What I liked in the class is that if another call is attempted when this one is running, it doesnât crash the app with âthereâs another process running nowâ. I noticed that on the URLConnection.Send. With yours, I tested a loop of 100 adds and then started another thread with another loop of 100 adds, and they all added. I donât think I couldâve gotten that with just the .Send. Iâm sure many of you could get that to work with the appropriate sleeps/polls, but that is too advanced for me at this time. Maybe someday
Youâre right that it has some advantages. I just meant that it was created at a point in time where such thing wasnât provided by Xojo. But Xojo now fills that gap, so itâs not a class that really needs to exist anymore.
I am thinking of refactoring some of my code to make use of either SendSync (in a thread) or your SynchronousHTTPSocket (in a thread).
If SendSync is still a performance nightmare then your socket still needs to exist