Atozed Forums

Full Version: Webservice demo ?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi Guys,

Merry Christmas everyone. I hope you have had some nice holidays.

I just completed a SOAP Webservice example with Server and Client, and are now wondering if there are any similar demo projects around, to use with IntraWeb.

I have a Windows program running on remote units around the world, which connects to my database (MS SQL) using a SOAP Webservice. The WebService is an MS SQL End-point, consisting of a number of stored procedures all added to an endpoint and published as a HTTP.SYS Webservice on the SQL 2008 server. The system is about 10 years old.

After updating to SQL 2017, endpoints is discontinued, so to make it work again, I'll have to create my own SOAP Webservice to repond to requests from the remote clients. I want the WebService server to reside as a stand alone application, like my IntraWeb SA application, on the MS SQL server, without depending on IIS or other page provider.

That's why I am looking for a demo showing how I can be done. Anybody know where I should look ?

NB! The above mentioned test also runs on my SQL server as an EXE file and it responds nicely to requests from the client on my workstation, so I could probably use it, but currently the appl is running as a visual windows program. A solution could be to make it run like a service.

Regards
Soren
Howdy Soren!

First, Happy Holidays!

I just finished adding the Viator REST API to my IW Web Reservations module and it was actually very easy. I used IW's content handlers.

Since I am assuming you are using the WRONG language (Delphi <lol>), here is an example of using Content Handlers supplied by IW's own guru Alexandre:

https://github.com/Atozed/IntraWeb/tree/...ntHandlers

I don't think setting up a SOAP API would be anymore difficult than a REST API.

All the best and Happy New Year!

Shane
Howdy Shane,

Thanks for your reply and advice. I've looked at the demo and can see how a call to a certain URL, through the ServerControllerBaseConfig setup, will be activating a named form, which of course could handle all data in and out of my database, but what I do not see from the example is how to transport the data from the client to the server and vice versa. Like the client sends a customer Id, and want the name and address information send back. Is it all done as request parameters in the http:// address line or is there another datastructure being sent along. With soap all is in the XML document being sent / received.

How do you transport reservation requests and response to and from your clients and server, this way ?

Regards
Soren
(12-29-2019, 10:01 AM)SorenJensen Wrote: [ -> ]Howdy Shane,

Thanks for your reply and advice. I've looked at the demo and can see how a call to a certain URL, through the ServerControllerBaseConfig setup, will be activating a named form, which of course could handle all data in and out of my database, but what I do not see from the example is how to transport the data from the client to the server and vice versa. Like the client sends a customer Id, and want the name and address information send back. Is it all done as request parameters in the http:// address line or is there another datastructure being sent along. With soap all is in the XML document being sent / received.

How do you transport reservation requests and response to and from your clients and server, this way ?

Regards
Soren
Howdy Soren,


Use the body of the request input data and the body of the response for output.

Since you are using SOAP,  you will be using XML (I assume) document type.

Below is my Viator REST API handler code (it is in C++):


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TViatorRestAPIHandler::TViatorRestAPIHandler()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
__fastcall TViatorRestAPIHandler::TViatorRestAPIHandler(void)
{
mFileMustExist = false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TViatorRestAPIHandler::Execute()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool __fastcall TViatorRestAPIHandler::Execute ( Iw::Http::Request::THttpRequest * pRequest,
    Iw::Http::Reply::THttpReply * pReply,
                                      const System::UnicodeString strPathname,
                                      Iwapplication::TIWApplication * pSession,
                                      System::Classes::TStrings * pParams
                                  )
{
// Keep compiler happy
  NOT_USED(pParams);
  NOT_USED(pSession);
  NOT_USED(pParams);
  NOT_USED(strPathname);

  // Get Request XML
  UnicodeString strRequestXML;
  if (pRequest->Files->Count == 1)
  {
    try
    {
THttpFile * pFile = pRequest->Files->Items[0];
  TFileStream * pFileStream = new TFileStream(pFile->TempPathName,fmOpenRead | fmShareDenyNone);
  TStringStream * pXMLStream = new TStringStream;

      try
      {
        pXMLStream->CopyFrom(pFileStream,0);
        strRequestXML = pXMLStream->DataString;
      }
      __finally
      {
        delete pFileStream;
        delete pXMLStream;
      }
  }

    catch (Exception &)
    {
    // Just eat as an empty XML error will be returned
    }
  }

  // Process Viator request
  pReply->ContentType = L"application/xml";
  pReply->Code = 200;
  try
  {
    // Create Viator API object
    TViatorAPIDataModuleUniquePtr objViatorAPIDataModulePtr(new TViatorAPIDataModule(NULL));

    // Process request
    SSStringListUniquePtr objResponseListPtr;
    objViatorAPIDataModulePtr->ProcessRequest(strRequestXML,objResponseListPtr);

    // Set response
  pReply->WriteString(objResponseListPtr->Text);
  }

  catch (Exception & objException)
  {
    // Set response
  pReply->WriteString(objException.Message);
  }

  return true;
}

The key parts you want to look at is in the Execute how to fetch the body of the SOAP request and then how to write out the response.

Hope this helps.

Happy New Year!

Shane
Delphi has some built in web services support: http://docwiki.embarcadero.com/RADStudio...b_Services

You should also look into Remobjects remoting SDK for Delphi. That's what I use for SOAP webservices.
SOAP is more of a PITA to parse than RESTstuff, I suggest using a library. The 3rd party services I connect to are straightforward enough to use the Delphi SOAP libraries, even from earlier Delphi versions.

Dan
Hi Shane, Ioan and Dan,

Happy New Year to you all. And thanks for your replies.

@Shane: Thanks for your C++ example. I'm not fluent in C++ but do understand most of your example. As far as I can read it, the data you are transporting between client and server, is done in an XML doc, which is attached to the request as a file. But how is that file attached to the request. Is it part of the http://www.xxxx.xx address line, or is it a build-in function of the request block ?

@ioan: Thanks for the link. I've been through that as part of completing the SOAP Server / Client example and have now taken it further and actually made it into a stand alone service, which I have installed and have running on my server. With a price starting at 700 US$ for RemObjects Remoting SDK, currently it is not an option. It might be later and I expect I will try it for free as they offer, but the final solution right now, will have to be without. But thanks for the hint.

@Dan: With the ChapmanWorld SOAP Client and Server example from 2015, both the client and the server is not wrapping or unwrapping any actual XML and coding the call and data handling is more like standard Delphi coding, like in this example on the client:

var  Prd  : Product;
begin
  Prd      := Product.create;
  Prd      := (HTTPRIO1 as SoapApiSoap).GetProduct(strtoint(IWEdit1.Text));
  IWLabel1.Caption := Prd.ProductName;
  IWlabel2.Caption  := Prd.Price.tostring;

Using Delphi's SOAP Server Application wizard makes it easy to work with, but combining it with Delphis Windows Service Wizard, to turn an ISAPI DLL into a HTTP.SYS Stand Alone WebService, makes it a bit more complicated.

And with the client on my workstation, I do get both WDSL and the functionality of the example, sent between the two. However, the example server part (the xxxintf and xxximpl pas files) is just returning the data it receives. I need to figure out how to get data in a table in a database and send back to the client, and could use a few hints. I suppose it is in the xxximpl.pas file it's done, but as it has no form, dropping a connection and query component on it is not an option. They will have to be created at runtime.

And it leads me to a question I hope one of you know the answer to: Using an ADOConnection to connect to an MS SQL server (with SQLOLEDB.1 as Provider) and a ADOQuery to execute (open) a "Select xxx from yyy", in the xxximpl.pas file, the ADO connection will be activated and deactivated for every query call. Is that the preferred way ?

Regards
Soren