i have link for use web service.
http://smartcard.rmto.ir:7003/i/web_service/PKG_WEB_SERVICES.xml
and i use this code in delphi,but it is not work.
procedure TForm1.Button1Click(Sender: TObject);
var
d : PKG_WEB_SERVICESPortType;
begin
Memo1.Lines.Clear;
d := GetPKG_WEB_SERVICESPortType(true,'http://smartcard.rmto.ir:7003/i/web_service/PKG_WEB_SERVICES.xml',nil);
Memo1.Lines.Text := d.GET_DRIVER_BY_SHC(Edit1.Text);
end;
web service
username:tr_web_service
password:tr_web_service123
thanks
You need read some information about SOAP. See SOAP in Delphi. Try get WSDL file.
Related
I have a web service client created with DELPHI XE 5, i used THTTPRIO, imported wsdl and created the ".pas" files.
The server of web service request a preemptive basic authentication (that work fine with SoapUI);
I know how to make authentication with user and password of THTTPReqResp.
rio := THTTPRIO.Create(nil);
HTTPReqResp1 := THTTPReqResp.Create(rio);
HTTPReqResp1.UserName := sUserName;
HTTPReqResp1.Password := sPasswordEncrypted;
But I don't connect to the web service because I don't know ho to make preemptive and if it's possible in Delphi.
Can anyone help me ? :)
I just found how It's possible to use "preemprive" connexion in DELPHI.
You have to modify the OnBeforePost of your "rio.HTTPWebNode" like this :
var
rio : THTTPRIO;
HTTPReqResp1: THTTPReqResp;
uselessObject: TUselessClass;
try
rio := THTTPRIO.Create(nil);
uselessObject := TUselessClass.Create();
rio.HTTPWebNode.GetHTTPReqResp.OnBeforePost :=
uselessObject.HTTPRIOHTTPWebNode1BeforePost;
With this procedure :
procedure TUselessClass.HTTPRIOHTTPWebNode1BeforePost(const HTTPReqResp: THTTPReqResp; Data: Pointer);
var
auth,toEncode: string;
begin
toEncode := Format('%s:%s',[sUserName,sPasswordEncrypted]);
auth := 'Authorization: Basic ' + TIdEncoderMIME.EncodeString(toEncode);
HttpAddRequestHeaders(Data, PChar(auth), Length(auth), HTTP_ADDREQ_FLAG_ADD);
end;
Hello everyone who reads this! I hope you can help me with my problem, but if not, thank you for try. I have DataSnap server and client. DataSnap server methods can return to client a DataSet as function result. I'm getting data from MySQL DB with TFDQuery component. Somebody please help me to understand, how can I get a dataset from FDQuery component that already has data?
TDataSet.Data is OleVariant type property containing all data. But FDQuery doesn't have the same property. I need to return a dataset from FDQuery as OleVariant in function.
*Try, Except, FreeAndNil, DisposeOf etc removed from code for better understanding the problem
//Client side
procedure TForm1.GetDataSetFromServer;
var
Server: TServerMethods1Client;
DS: TClientDataSet;
begin
Server := TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection);
DS := TClientDataSet.Create(nil);
DS.Data := Server.GetDataSet; //Call remote server method
end;
//DataSnap server side
function TServerMethods1.GetDataSet: OleVariant;
begin
FDQuery1.Close;
FDQuery1.SQL.Text := 'SELECT * FROM Table1';
FDQuery1.Open;
//Now i need to return all data as function result
result := ???
end;
Need any information that can be helpful. Thanks in advance! Have a nice day!
The simplest way to do this, AFAIK, is to add a TDataSetProvider, and also a TClientDataSet (if you don't already have one) to your Server module.
Then, you can modify your server code as follows:
function GetDataSet: OleVariant;
begin
if ClientDataSet1.Active then
ClientDataSet1.Close;
FDQuery1.Close;
FDQuery1.SQL.Text := 'SELECT * FROM Table1';
// FDQuery1.Open; Leave this to the DataSetProvider/ClientDataSet
//Now i need to return all data as function result
//result := ???
DataSetProvider1.DataSet := FDQuery1;
ClientDataSet1.ProviderName := 'DataSetProvider1';
ClientDataSet1.Open;
Result := ClientDataSet1.Data;
end;
The point of doing it this way is that TDataSetProvider has all the internal machinery necessary to package up its DataSet's data (i.e. FDQuery1's data) in a form that that can be sent between ClientDataSets. Incorporating the DataSetProvider in the server minimizes the code necessary in the client to consume the CDS data.
Btw, I'm assuming that your server module has the code necessary to 'export' GetDataSet as a server method.
You can also do return a TDataSet from the server function:
function TServerMethods1.GetDataSet: TDataSet;
begin
if ClientDataSet1.Active then
ClientDataSet1.Close;
FDQuery1.Close;
FDQuery1.SQL.Text := 'SELECT * FROM Table1';
DataSetProvider1.DataSet := FDQuery1;
ClientDataSet1.ProviderName := 'DataSetProvider1';
ClientDataSet1.Open;
Result := ClientDataSet1;
end;
For the client side, it now depends on what kind of server you are using.
If it is a DBX Datasnap Server, you will have to use a TsqlServerMethod (note the lower case) 'sql' here, and a TDataSetProvider with a TClientDataset, all preconfigured to retrieve the data from that Server.
If it is a REST Datasnap server, you can do this at the client:
procedure TfrmClientMain.btnRefreshClick(Sender: TObject);
var
Server: TServerMethods1Client;
lDataSet: TDataSet;
DSP: TDataSetProvider;
begin
Server := TServerMethods1Client.Create(ClientModule1.DSRestConnection1);
try
CDS.Close; // a TClientDataSet has been placed on the form
lDataSet := Server.GetDataSet();
DSP := TDataSetProvider.Create(Self);
try
DSP.DataSet := lDataSet;
CDS.SetProvider(DSP);
CDS.Open;
finally
CDS.SetProvider(nil);
DSP.Free;
end;
finally
Server.Free;
end;
end;
I am using Delphi XE7. I need to access the request headers in DataSnap Server, but it does no seem to have this option. In DataSnap REST, it is possible, because TWebModule is available.
This code does not work, like in REST:
function TServerMethods1.EchoString(Value: string): string;
var
Module: TWebModule;
begin
Module := GetDataSnapWebModule;
Result := Module.Request.RemoteIP + ': ' + Value;
end;
Does anyone have an idea about DataSnap Server?
I update my project for REST, and resolved my problem in access Header. With the following code:
Need declare Web.HTTPApp at uses
var
oWebModule: TWebModule;
sHeader: String;
begin
oWebModule := GetDataSnapWebModule;
sHeader := oWebModule.Request.Content;
end;
Hi i need help on how to retrieved the parameters and data using IdHttpServer from indy.
many of my application uses TIdMultiPartFormDataStream to send data over the php. I would like to use the TIdHTTPServer to verify parameters for some reason and forward the request to its destination.
i created a short example for you to see.
uses
IdContext, IdMultipartFormData;
// Server Side------------------------------------------------
IdHTTPServer1.Defaultport := 88;
IdHTTPServer1.active := True;
procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
// the request will be pass through its destination by POST/GET
// and send the result back to the client apps.
AResponseInfo.ContentText := ARequestInfo.Params.Text;
end;
// Client Side------------------------------------------------
// This will work using the standard Post or Get
procedure TForm1.btnPost1Click(Sender: TObject);
var
sl: TStringList;
res: String;
begin
sl := TStringList.Create;
try
sl.Add('Param1=Data1');
sl.Add('Param2=Data1');
sl.Add('Param3=Data2');
sl.Add('Param4=Data3');
res := IdHTTP1.Post('http://localhost:88/some.php', sl);
ShowMessage(res);
finally
sl.Free;
end;
end;
//how can i get the parameters and value for this code in my IdHttpServer
procedure TForm1.btnPost2Click(Sender: TObject);
var
mfd: TIdMultiPartFormDataStream;
res: String;
begin
mfd := TIdMultiPartFormDataStream.Create;
try
mfd.AddFormField('Param1', 'Data1');
mfd.AddFormField('Param2', 'Data1');
mfd.AddFormField('Param3', 'Data2');
mfd.AddFormField('Param4', 'Data3');
res := IdHTTP1.Post('http://localhost:88/some.php', mfd);
ShowMessage(res);
finally
mfd.Free;
end;
end;
and how would i know if the Client apps pass a TIdMultiPartFormDataStream type of parameter?
This has been asked and answered many times before in the Embarcadero and Indy forums. Please search through their archives, as well as other archives, like Google Groups, to find code examples.
In a nutshell, when the TIdHTTPServer.OnCommandGet event is triggered, if the AResponseInfo.ContentType property says multipart/form-data (the version of TIdHTTP.Post() you are using will send application/x-www-form-urlencoded instead), the AResponseInfo.PostStream property will contain the raw MIME data that the client posted. You can use the TIdMessageDecoderMIME class to parse it. However, that class was never intended to be used server-side, so it is not very intuitive to use, but it is possible nontheless.
In Indy 11, I am planning on implementing native multipart/form-data parsing directly into TIdHTTPServer itself, but there is no ETA on that yet as we have not started work on Indy 11 yet.
I have built the worlds dumbest and most simple SOAP server, in about 3 clicks, in visual studio. The exact steps in visual studio 2010: First create a new project as a web application, Then add a new item of type web service. (See accepted answer here for picture.) That soap server service Service1 has a simple method GetData:
A snippet from clientService1.pas, created using WSDL importer...
IService1 = interface(IInvokable)
['{967498E8-4F67-AAA5-A38F-F74D8C7E346A}']
function GetData(const value: Integer): string; stdcall;
function GetDataUsingDataContract(const composite: CompositeType2): CompositeType2; stdcall;
end;
When I try to run this method, like this:
procedure TForm3.Button1Click(Sender: TObject);
var
rio : THTTPRIO;
sv:IService1;
addr : string;
data : string;
begin
//addr := '....'; // url from visual studio 2010 live debug instance.
rio := THTTPRIO.Create(nil);
sv := GetIService1( true, addr, rio );
try
data := sv.GetData( 0);
Button1.Caption := data;
finally
sv := nil;
rio.Free;
end;
end;
The error I get is this:
ESOAPHTTPException:
The handle is in the wrong state for the requested operation -
URL:http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary1/Service1/ -
SOAPAction:http://tempuri.org/IService1/GetData'.
The URL works fine when I paste the url above into a web browser, so the usual answer that the SOAP code in Delphi has the tendency to not notice an HTTP failure, does not seem likely. Rather it seems that I am either (a) experiencing breakage in WinInet (known to happen in some versions of windows), or (b) doing something wrong?
It seems to me that anybody who has visual studio and delphi both installed, should be able to try to get the dummy starter Soap server in Visual Studio talking to the soap client in Delphi, without any effort at all. But I can not figure out the simplest things.
At one time there was a discussion about the error in a conversation now long since deleted from Embarcadero forums, by Bruneau Babet, an embarcadero staffer.
Bruno said:
Hello,
I've posted a patched version of SOAPHTTPTrans.pas that contains a fix
for this issue here:
[forum link redacted, it didn't work anymore anyways, the post is gone]
You may still override the event as described in the C++Builder
section referred; or, much simpler, at least for Delphi users, simply
add the updated SOAPHTTPTrans.pas to your app's project. Let us know
if that does not work for you.
Cheers,
Bruneau
You can get the repair and the notes about it in its original forum formatting from the following pastebin link and on bitbucket so you don't have to extract the file from the surrounding text.
Warren Update 2016: I have been informed by someone who tried to use the fix on Delphi XE that this fix does NOT work for them in Delphi XE. Any further updates to the code in bitbucket that resolve the remaining bugs would be appreciated.
I ran into the The handle is in the wrong state for the requested operation issue in November 2018 using Delphi Tokyo 10.2.3, then looked at the code patch in the pastebin link under Arjen's answer.
That code is very old and the test code no longer works (SOAP service unavailable). Also, it is unclear from Bruneau's code what he patched exactly.
Comparing that source and the one from my Delphi version it seems that these are the (two) required modifications in the HandleWinInetError procedure ('PATCH HERE'):
function THTTPReqResp.HandleWinInetError(LastError: DWord;
Request: HINTERNET;
RaiseError: Boolean): DWord;
function CallInternetErrorDlg: DWord;
var
P: Pointer;
begin
Result := InternetErrorDlg(GetDesktopWindow(), Request, LastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
{ After selecting client certificate send request again,
Note: InternetErrorDlg always returns ERROR_SUCCESS when called with
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED }
if LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then
Result := ERROR_INTERNET_FORCE_RETRY;
end;
const
{ Missing from our WinInet currently }
INTERNET_OPTION_CLIENT_CERT_CONTEXT = 84;
var
Flags, FlagsLen, DWCert, DWCertLen: DWord;
ClientCertInfo: IClientCertInfo;
CertSerialNum: string;
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
hStore: HCERTSTORE;
CertContext: PCERT_CONTEXT;
{$ENDIF}
begin
{ Dispatch to custom handler, if there's one }
if Assigned(FOnWinInetError) then
Result := FOnWinInetError(LastError, Request)
else
begin
Result := ERROR_INTERNET_FORCE_RETRY;
{ Handle INVALID_CA discreetly }
if (LastError = ERROR_INTERNET_INVALID_CA) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
end
else if (LastError = ERROR_INTERNET_SEC_CERT_REV_FAILED) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_REVOCATION;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
end
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and
Supports(Self, IClientCertInfo, ClientCertInfo) and
(ClientCertInfo.GetCertSerialNumber <> '') then
begin
CertSerialNum := ClientCertInfo.GetCertSerialNumber();
hStore := ClientCertInfo.GetCertStore();
if hStore = nil then
begin
hStore := CertOpenSystemStore(0, PChar('MY'));
ClientCertInfo.SetCertStore(hStore);
end;
CertContext := FindCertWithSerialNumber(hStore, CertSerialNum);
if CertContext <> nil then
begin
ClientCertInfo.SetCertContext(CertContext);
InternetSetOption(Request, INTERNET_OPTION_CLIENT_CERT_CONTEXT,
CertContext, SizeOf(CERT_CONTEXT));
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end
{$ENDIF}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and (soPickFirstClientCertificate in InvokeOptions) then
begin
{ This instructs WinInet to pick the first (a random?) client cerficate }
DWCertLen := SizeOf(DWCert);
DWCert := 0;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
Pointer(#DWCert), DWCertLen);
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end;
end;
Note that the RaiseError procedure parameter was not even used before this patch ;-)
Here is some test code using the SOAP service from NOAA's National Digital Forecast Database (NDFD) SOAP Web Service:
Uses SOAP.SOAPHTTPTrans;
const Request2 =
'<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">' +
' <soapenv:Header/>' +
' <soapenv:Body>' +
' <ndf:NDFDgenByDay soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
' <latitude xsi:type="xsd:decimal">38.9936</latitude>' +
' <longitude xsi:type="xsd:decimal">-77.0224</longitude>' +
' <startDate xsi:type="xsd:date">%tomorrow%</startDate>' +
' <numDays xsi:type="xsd:integer">5</numDays>' +
' <Unit xsi:type="dwml:unitType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">e</Unit>' +
' <format xsi:type="dwml:formatType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">12 hourly</format>' +
' </ndf:NDFDgenByDay>' +
' </soapenv:Body>' +
'</soapenv:Envelope>';
const URL2= 'https://graphical.weather.gov:443/xml/SOAP_server/ndfdXMLserver.php';
procedure TFrmHandleWinINetError.Button1Click(Sender: TObject);
var
RR: THTTPReqResp;
Response: TMemoryStream;
U8: UTF8String;
begin
RR := THTTPReqResp.Create(nil);
try
try
RR.URL := URL2;
RR.UseUTF8InHeader := True;
RR.SoapAction := 'NDFDgenByDay';
Response := TMemoryStream.Create;
RR.Execute(Request2, Response);
SetLength(U8, Response.Size);
Response.Position := 0;
Response.Read(U8[1], Length(U8));
ShowMessage(String(U8));
except
on E:Exception do ShowMessage('ERROR CAUGHT: ' + e.message);
end;
finally
Response.Free;
RR.Free;
end;
end;
end;
Without the patch errors in the tail end of the URL are caught, but errors in the domain name just trigger an empty error message.
With the patch those are also caught.
I have a reported the issue in the RAD Studio Quality Portal under number RSP-21862
Use at your own risk and please report any additional findings.
Addition: The issue was fixed in Dec 2018 in Delphi 10.3 Rio and the Quality Portal issue was closed with the following remark:
In RAD Studio 10.3 the implementation of THTTPReqResp was changed and replaced with THTTPClient. So, this issue no longer applies.
I have not verified this.