Access remote database using DataSnap technology in C++ Builder 10.1 Berlin - delphi

How to query and get results from remote database using DataSnap technology in C++ Builder 10.1 Berlin ?
I want to build a simple solution having two VCL Forms Applications, like client(1) and server(2), running on two different windows os computers, connected on same local network.
But I cannot accomplish this simple task and this is what I tried to do:
On the server application (2), I use:
TSQLConnection *SQLConnection1;
TSQLQuery *SQLQuery1;
and I will load a SQLite database version 3:
if (SQLConnection1->Params->IndexOf("Database") == -1)
{
SQLConnection1->Params->Add("Database="+Form->DataBaseFile );
}
else
{
SQLConnection1->Params->Values["Database"] = Form->DataBaseFile;
}
try
{
SQLConnection1->Connected = true;
}
catch (EDatabaseError& E)
{
ShowMessage("Exception raised with message" + E.Message);
}
and execute sql query:
try
{
SQLQuery1->SQL->Text = "query from client app(1)";
SQLQuery1->Active = false;
SQLQuery1->ExecSQL();
}
catch (Exception& E)
{
ShowMessage( "SQLite exception raised with message:\n\n" + E.Message);
SQLConnection1->Connected = false;
}
and I need to return SQLQuery1 results back to client app(1)
On the client application I think I should do something like below, but I'm not sure, I don't know how to do this correctly:
TSQLServerMethod *SQLServerMethod1;
SQLServerMethod->SQLConnection = SQLConnection1;
try{
SQLServerMethod.ServerMethodName = "TDSUtilityMethods.echoOutStr";
SQLServerMethod->Params[0]->AsString = "123";
SQLServerMethod->ExecuteMethod();
memoOutput->Text = SQLServerMethod->Params[1]->AsString;
}
finally{
SQLServerMethod->Close();
}
So the purpose is to make a server application(2) which host and execute sql queries from client app(1) which sends the sql query and waits for results. The application(1) which send sql query is a wrapper of chromium client. I tried to achieve all this solution using TIdHTTPServer on sever app(2) and WebSockets from chromium client app(1), and posted a releated question here but implementing WebSocket protocol(encoding/decoding packets) is a bit hard for an amateur developer. And then I found that a easier solution could be using DataSnap technology. I have read about Developing DataSnap Applications, but still not able to build this simple solution, on embarcadero website are described each component, but because I'm amateur developer, I found it confusing and hard to complete a simple task which seems possible and easier to build using DataSnap technology than WebSockets. But now I found hard to implement DataSnap technology, because there is a lot of new things which are confusing without examples.
Please if you know how to do this in C++ Builder 10.1 Berlin, show here a short sample of that.

Related

Using Neo4j with React JS

Can we use graph database neo4j with react js? If not so is there any alternate option for including graph database in react JS?
Easily, all you need is neo4j-driver: https://www.npmjs.com/package/neo4j-driver
Here is the most simplistic usage:
neo4j.js
//import { v1 as neo4j } from 'neo4j-driver'
const neo4j = require('neo4j-driver').v1
const driver = neo4j.driver('bolt://localhost', neo4j.auth.basic('username', 'password'))
const session = driver.session()
session
.run(`
MATCH (n:Node)
RETURN n AS someName
`)
.then((results) => {
results.records.forEach((record) => console.log(record.get('someName')))
session.close()
driver.close()
})
It is best practice to close the session always after you get the data. It is inexpensive and lightweight.
It is best practice to only close the driver session once your program is done (like Mongo DB). You will see extreme errors if you close the driver at a bad time, which is incredibly important to note if you are beginner. You will see errors like 'connection to server closed', etc. In async code, for example, if you run a query and close the driver before the results are parsed, you will have a bad time.
You can see in my example that I close the driver after, but only to illustrate proper cleanup. If you run this code in a standalone JS file to test, you will see node.js hangs after the query and you need to press CTRL + C to exit. Adding driver.close() fixes that. Normally, the driver is not closed until the program exits/crashes, which is never in a Backend API, and not until the user logs out in the Frontend.
Knowing this now, you are off to a great start.
Remember, session.close() immediately every time, and be careful with the driver.close().
You could put this code in a React component or action creator easily and render the data.
You will find it no different than hooking up and working with Axios.
You can run statements in a transaction also, which is beneficial for writelocking affected nodes. You should research that thoroughly first, but transaction flow is like this:
const session = driver.session()
const tx = session.beginTransaction()
tx
.run(query)
.then(// same as normal)
.catch(// errors)
// the difference is you can chain multiple transactions:
const tx1 = await tx.run().then()
// use results
const tx2 = await tx.run().then()
// then, once you are ready to commit the changes:
if (results.good !== true) {
tx.rollback()
session.close()
throw error
}
await tx.commit()
session.close()
const finalResults = { tx1, tx2 }
return finalResults
// in my experience, you have to await tx.commit
// in async/await syntax conditions, otherwise it may not commit properly
// that operation is not instant
tl;dr;
Yes, you can!
You are mixing two different technologies together. Neo4j is graph database and React.js is framework for front-end.
You can connect to Neo4j from JavaScript - http://neo4j.com/developer/javascript/
Interesting topic. I am using the driver in a React App and recently experienced some issues. I am closing the session every time a lifecycle hook completes like in your example. When there where more intensive queries I would see a timeout error. Going back to my setup decided to experiment by closing the driver in some more expensive queries and it looks like (still need more testing) the crashes are gone.
If you are deploying a real-world application I would urge you to think about Authentication and Authorization when using a DB-React setup only as you would have to store username/password of the neo4j server in the client. I am looking into options of having the Neo4J server issuing a token and receiving it for Authorization but the best practice is for sure to have a Node.js server in the middle with something like Passport to handle Authentication.
So, all in all, maybe the best scenario is to only use the driver in Node and have the browser always communicating with the Node server using axios...

Are there version options for Indy SNMP traps?

I'm using Embarcadero RAD Studio XE3 with its TIdSNMP Indy SNMP component to prepare and send SNMP trap notifications to an Enterprise Server. I set up to 12 varbinds depending on the trap type, and Wireshark is seeing and properly dissecting the traps on the target host. It appears that my end is working fine.
The Manager side of this system does not seem to recognize these traps and can't decode them according to the implementation team. They have pointed to the SNMP version item in the trap itself, which is 'v2u'. Because this version is deprecated, they would like to see version 'v2c', and they assert that all their other traps are this version.
The question is, do I have any options as far as what version of trap to send? I see TIdSNMP::Trap has a Version member; is it as simple as setting this to 3?
This is the code I'm using:
void SendTrap(int atcsfield)
{
/* TIdSnmp *snmp = new TIdSNMP(0); */
snmp->Trap->Clear();
snmp->Trap->Version = 2;
snmp->Trap->Community=String(cfg.snmp.community);
snmp->Trap->TimeTicks = GetTickCount() - InitialTickCount;
snmp->Trap->Enterprise=String(cfg.snmp.oid);
snmp->Trap->GenTrap=6;
snmp->Trap->SpecTrap=1;
for(int i=0;i<MAX_VARBINDS;i++)
{
if(svb[i].Length())
{
varb.sprintf("%s.1.%d",BaseOID.c_str(),i);
snmp->Trap->MIBAdd(varb,svb[i], ASN1_OCTSTR);
}
}
for(int i=0;i<MAX_VARBINDS;i++)
{
if(ivb[i]!=-1)
{
varb.sprintf("%s.1.%d",BaseOID.c_str(),i);
snmp->Trap->MIBAdd(varb, ivb[i], ASN1_INT);
}
}
snmp->Host = ManagerIpList->Strings[j];
snmp->SendTrap();
}
At this time, TIdSNMP only supports SNMPv1. Setting Trap->Version to 2 does not send a v2/v3 formatted trap, as the layout of the trap PDU is different between v1 and v2/v3.
Support for newer SNMP versions is on Indy's todo list:
Update TIdSNMP to support newer SNMP versions
https://code.google.com/p/indyproject/issues/detail?id=139
http://indy.codeplex.com/workitem/19076

WinHttpWriteData seems to be "flooding" server

I'm using WinHttpSendRequest/WinHttpWriteData to upload a large (54Mb) file to our server, sending it in 4Kb lumps to give user feedback. This has been working well, as far as I know, until recently. Now, when I try it, the upload goes very quickly and then the WinHttpReceiveResponse() call times-out and incomplete data is received by the server.
I'm using Win 8.1 64bit, IE11 11.0.15 (I think that WinHttp is updated with IE) but on my colleague's PC - same version of Windows, IE, the upload is much slower and the response doesn't time-out. When I try testing on various virtual machines, the problem isn't apparent. Other colleagues, however ... oh Windows!!
Just to be clear
As far as I am aware, this code used to work!
WinHttpOpen is called without the ASYNC flag set.
The HTTP verb is POST
The code in Delphi XE2
Result:= WinHttpSendRequest(RequestHandle,PWideChar(Headers),Length(Headers),WINHTTP_NO_REQUEST_DATA,0,FormBuffer.Size,Cardinal(Self));
If Result
then begin
BytesToWrite:= FormBuffer.Size;
while BytesToWrite > 0
do begin
If BytesToWrite > SizeOf(WriteBuffer)
then BufFill:= SizeOf(WriteBuffer)
else BufFill:= BytesToWrite;
FormBuffer.ReadBytes(WriteBuffer,BufFill); // FormBuffer is my object to supply data and headers
If WinHttpWriteData(RequestHandle,#WriteBuffer[0],BufFill,Written)
then Dec(BytesToWrite,Written)
else Error('WinHttpWriteData'); // Error() method calls GetLastError, assembles error message and logs it
If Assigned(OnDataWrite)
then OnDataWrite(Self,Written); // Event that notifies user
end;
FetchResponse(RequestHandle); // Calls WinHttpReceiveResponse() and then fetches data
Result:= True;
end
else GLE:= Error('WinHttpSendRequest');
This code was largely an adaptation of this code:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa384120(v=vs.85).aspx
The "WinHttp Sample code to do a PUT." at the bottom.
It's AVG ...!
Disabling AVG gives normal performance for the upload ... now it's just a matter of finding out which part(s) are getting in the way.

Why would a WMI query fail sometimes, but not others?

I run the same code from two different locations in my application. I know it is the same code, because it is in a class and that class only has one publicly facing function. Both places call the function with the same arguments and both are running in the UI thread.
The function does a search for a particular printer by name using an asynchronous WMI query-->
var searcher =
new ManagementObjectSearcher(
"SELECT * from Win32_Printer WHERE Name LIKE '%ZDesigner GX430t'");
// Create an observer to trigger a callback when the search is completed.
var watcher = new ManagementOperationObserver();
watcher.Completed += PrinterSearchCompleted;
watcher.ObjectReady += PrinterSearchReady;
// Look for the printer
_printerFound = false;
_searchCompleted = false;
searcher.Get(watcher);
The problem I am having is that the ObjectReady event is not triggered when I run it from one location and when I run it from another, it get's triggered all the time.
Also, another problem is that this seems to be computer specific; some of the computers I run this on work just fine, others exhibit the problem I described above.
Any ideas what I should be looking for?
Couple of things to try:
Check if WMI service is running on all the computers.
Restart WMI service on the computers where it is not working.
You may find this article useful.
If its a Windows 7 or Windows Server 2008 R2 server, WMI has a memory leak problem. Check this.

Connect to MySQL from Microsoft Data Application Block

lI am using the Data Application block for a majority of my data access, specifically using the SqlHelper class to call the ExecuteReader, ExecuteNonQuery, and like methods. Passing the connection string with each database call.
How can I modify this to enable connection to a MySQL database as well.
If you've got the Enterprise Library installed and already know how to connect to SQL Server databases, connecting to MySQL databases is not any harder.
One way to do it is to use ODBC. This is what I did:
Go to MySQL.com and download the latest MySQL ODBC connector. As I write this it's 5.1.5. I used the 64-bit version, as I have 64-bit Vista.
Install the ODBC Connector. I chose to use the no-installer version. I just unzipped it and ran Install.bat at an administrator's command prompt. The MSI version probably works fine, but I did it this way back when I installed the 3.51 connector.
Verify the installation by opening your ODBC control panel and checking the Drivers tab. You should see the MySQL ODBC 5.1 Driver listed there. It seems to even co-exist peacefully with the older 3.51 version if you already have that. Additionally it coexists peacefully with the .NET connector if that is installed too.
At this point you will be doing what you've done to connect to a SQL Server database. All you need to know is what to use for a connection string.
Here's what mine looks like:
Of course you can set "name" to whatever you want.
If this is your only database, you can set it up as the defaultDatabase like this:
Access your data in your code like you always do! Here's a plain text sql example:
public List<Contact> Contact_SelectAll()
{
List<Contact> contactList = new List<Contact>();
Database db = DatabaseFactory.CreateDatabase("MySqlDatabaseTest");
DbCommand dbCommand = db.GetSqlStringCommand("select * from Contact");
using (IDataReader dataReader = db.ExecuteReader(dbCommand))
{
while (dataReader.Read())
{
Contact contact = new Contact();
contact.ID = (int) dataReader["ContactID"];
client.FirstName = dataReader["ContactFName"].ToString();
client.LastName = dataReader["ContactLName"].ToString();
clientList.Add(client);
}
}
return clientList;
}
Another way to do it is to build and use a MySql provider. This guy did that.
I learned how to do this by adapting these instructions for connecting to Access.
Oh, and here are some more MySql Connection String samples.

Resources