How can i import a https webservice (wcf) with Delphi 2010? - wcf

I have a problem so i wanna help from you.
There is a webservice and it's url : https://kps.saglik.gov.tr/Services/KPSTestServices.svc
We can import this url on visual studio c# easily, but we couldn't import it on delphi 2010.
Also we have a user id and password from saglik.gov.tr, but the result is same : can't import this service. What can we do now ?
Thanks for any idea from at the moment.
Visual Studio Sample : https://kps.saglik.gov.tr/kps_ornek1.zip
I was able to import files to your local hard disk recording.
https://kps.saglik.gov.tr/Services/KPSTestServices.svc?wsdl = services.wsdl
https://kps.saglik.gov.tr/Services/KPSTestServices.svc?wsdl=wsdl0 = secondry.wsdl
https://kps.saglik.gov.tr/Services/KPSTestServices.svc?xsd=xsd0 = xsd0.xsd
https://kps.saglik.gov.tr/Services/KPSTestServices.svc?xsd=xsd1 = xsd1.xsd
https://kps.saglik.gov.tr/Services/KPSTestServices.svc?xsd=xsd2 = xsd2.xsd
When I call service , Now I get the https connection failed error.
Xml created by the WCFStorm
(http://www.wcfstorm.com/wcf/home.aspx)
Header
POST https://kps.saglik.gov.tr/Services/KPSTestServices.svc HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
Host: kps.saglik.gov.tr
Content-Length: 1256
Expect: 100-continue
Connection: Keep-Alive
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">http://www.saglik.gov.tr/KPS/2011/KPSServices/TcKimlikNoIleKisiSorgula</a:Action><a:MessageID>urn:uuid:b99c1ef4-9e44-42b9-ae1f-9844bfc0f997</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">https://kps.saglik.gov.tr/Services/KPSTestServices.svc</a:To><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><u:Timestamp u:Id="_0"><u:Created>2011-09-13T11:17:27.234Z</u:Created><u:Expires>2011-09-13T11:22:27.234Z</u:Expires></u:Timestamp><o:UsernameToken u:Id="uuid-d7a725d3-aa3c-4336-8651-304ecdb8d5e0-4"><o:Username>myUserName</o:Username><o:Password o:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPassword</o:Password></o:UsernameToken></o:Security></s:Header><s:Body><TcKimlikNoIleKisiSorgula xmlns="http://www.saglik.gov.tr/KPS/2011"><tcNo>1842715****</tcNo></TcKimlikNoIleKisiSorgula></s:Body></s:Envelope>
Response XML
Header
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 1519
Content-Type: application/soap+xml; charset=utf-8
Server: Microsoft-IIS/7.5
Set-Cookie: ASP.NET_SessionId=0vdbbkozgztz4falycku4gr0; path=/; HttpOnly
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 13 Sep 2011 11:19:40 GMT
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">http://www.saglik.gov.tr/KPS/2011/KPSServices/TcKimlikNoIleKisiSorgulaResponse</a:Action><a:RelatesTo>urn:uuid:b99c1ef4-9e44-42b9-ae1f-9844bfc0f997</a:RelatesTo><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><u:Timestamp u:Id="_0"><u:Created>2011-09-13T11:19:41.255Z</u:Created><u:Expires>2011-09-13T11:24:41.255Z</u:Expires></u:Timestamp></o:Security></s:Header><s:Body><TcKimlikNoIleKisiSorgulaResponse xmlns="http://www.saglik.gov.tr/KPS/2011"><TcKimlikNoIleKisiSorgulaResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Hata i:nil="true"/><Sonuc><Ad>MUSTAFA</Ad><AileSiraNo>12</AileSiraNo><AnaAd>LEYLA</AnaAd><BabaAd>OSMAN</BabaAd><BireySiraNo>*</BireySiraNo><CiltAd>-</CiltAd><CiltKod>-</CiltKod><Cinsiyet>Erkek</Cinsiyet><Din i:nil="true"/><DogumTarihi>21.9.0000</DogumTarihi><DogumYer>*</DogumYer><Durum>Açık</Durum><Hata i:nil="true"/><IlAd>*</IlAd><IlKod>*</IlKod><IlceAd>Abana</IlceAd><IlceKod>*</IlceKod><MedeniHal>Bekar</MedeniHal><OlumTarih>0.0.0</OlumTarih><Soyad>*</Soyad><TCKimlikNo>18427***</TCKimlikNo><Yakinlik>Kendisi</Yakinlik></Sonuc></TcKimlikNoIleKisiSorgulaResult></TcKimlikNoIleKisiSorgulaResponse></s:Body></s:Envelope>
Delphi 2010
My Request
CONNECT kps.saglik.gov.tr:443 HTTP/1.0
User-Agent: Borland SOAP 1.2
Host: kps.saglik.gov.tr:443
Content-Length: 0
Proxy-Connection: Keep-Alive
Pragma: no-cache
No XML
My Response
Header
HTTP/1.1 502 Unable to Secure Connection
Via: 1.1 SYSTMG07
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
No XML

You need to point delphi towards the WSDL of the service. just append ?wsdl to the end of the first URL you gave: https://kps.saglik.gov.tr/Services/KPSTestServices.svc?wsdl and open this URL.
Save the file as a wsdl file and import it using: File -> New -> Other -> Delphi Projects -> Webservices -> WSDL Importer.
Please note: when the webservice changes you need to reimport. Also, using the webservice this way, you might need to deploy the wsdl with your application, depending on wether or not you are using the wsdl when consuming the webservice.

Maybe I am a little bit pessimistic about Delphi SOAP support, but I think this will be easier to solve using a "proxy" service written in C# (or Java, depending on available developer resources).
I have used a 'proxy' solution succesfully for the integration of a Microsoft Dynamics CRM system. After many attempts to solve it in Delphi, we finally wrote a simple C# application which reads input data from files (created from the Delphi app) and then invokes the web service operations using the data from these files.
Fortunately this was only a very simple one-way interface. For advanced requirements, the Delphi app could communicate over a TCP based protocol (HTTP) using XML or JSON payload. For bidirectional data exchange, the Delphi application would have to run a HTTP server too, which can be implemented with Indy in a couple of code lines. For bidirectional operation, using a messaging middleware like MSMQ (or one of the many open source message brokers like ActiveMQ or OpenMQ) can also be a good solution, because all applications can go offline for maintenance without the danger of message loss.

I just went through a similar problem attempting to connect a D2007 client to a C# service. The details I found were interesting. First of all the Delphi importer seriously under performed. I switched to RemObj and continued to have problems. At the end of the day there seems to be 3 items of interest when making the call to a WCF C# web service from a Delphi App. Those 3 items are as follows...
1) Make sure on the Delphi side you have the Soap version set to 1.2 (this is the easy one)
2) The post command being generated was including an incorrect action.
needed: POST "http://URI/Service/Command"
RemObj: POST urn:HCSConnect-WSHCSConnect#Ping
Delphi: ---post command missing completely---
What I did was change some details in the Rem Obj stuff and make it look like what I needed
3) With the service I was using the soap envelope wants a header area that contains a definition of a few details. In my situation the most important items in this header turned out to be the "a:Action" and "a:To" tags. These tags are missing in the Delphi apps, RemObj or otherwise. So in my situations I am intercepting the xml and filling it in.
The solutions to the last 2 items are not so simple... if you are using Rem Obj you can read about how I fixed it and what you can do the RemObj forum.
http://connect.remobjects.com/discussion/825/problem-calling-web-service-built-with-c
.... last but not least ...
I also got the thing to work using direct calls... if you are not using RemObj and Delphi is being a pain you can always just build your post and xml yourself and send it. Just like I did below... remember, post/xml/web it's all just plain text being sent back and forth.
procedure TMainForm.Button5Click(Sender: TObject);
procedure HandleError(const errorCode: integer);
var
errorMessage: AnsiString;
begin
SetLength(errorMessage, 256);
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_FROM_HMODULE,
Pointer(GetModuleHandle('wininet.dll')),
errorCode, 0, PChar(errorMessage), Length(errorMessage), nil);
SetLength(errorMessage, StrLen(PChar(errorMessage)));
raise Exception.Create(errorMessage);
end;
function BuildHeader: TStringStream;
begin
result := TStringStream.Create('');
try
result.WriteString('Content-Type: application/soap+xml;charset=UTF-8;action="http://Thermo.Connect/IHCSConnect/Ping"' + sLineBreak);
except
result.Free;
raise;
end;
end;
function BuildBody: TStringStream;
begin
result := TStringStream.Create('');
with result do
try
WriteString('<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">' + sLineBreak);
WriteString('<s:Header>' + sLineBreak);
WriteString('<a:Action>http://Thermo.Connect/IHCSConnect/Ping</a:Action>' + sLineBreak);
WriteString('<a:To>http://thermo-pc:2021/WSHCSConnect</a:To>' + sLineBreak);
WriteString('</s:Header>' + sLineBreak);
WriteString('<s:Body>' + sLineBreak);
WriteString('<Ping xmlns="http://Thermo.Connect">' + sLineBreak);
WriteString('</Ping>' + sLineBreak);
WriteString('</s:Body>' + sLineBreak);
WriteString('</s:Envelope>' + sLineBreak);
except;
result.Free;
raise;
end;
end;
var
InetRoot: HINTERNET;
InetConnect: HINTERNET;
Request: HINTERNET;
begin
InetRoot := InternetOpen('GabeCode', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
InetConnect := InternetConnect( InetRoot, 'thermo-pc:2021', 0, '',
'', INTERNET_SERVICE_HTTP, 0, Cardinal(Self));
try
Request := HttpOpenRequest( InetConnect, 'POST', 'WSHCSConnect', 'HTTP/1.1', nil, nil,
INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_NO_CACHE_WRITE,
0);
try
// build add header items to the post request
with BuildHeader do
try
HttpAddRequestHeaders(Request, PChar(DataString), Length(DataString), HTTP_ADDREQ_FLAG_ADD);
finally
Free;
end;
// build the body of data being posted and send the post
with BuildBody do
try
if not HttpSendRequest(Request, nil, 0, PChar(DataString), Length(DataString)) then
HandleError(GetLastError);
finally
Free;
end;
finally
InternetCloseHandle(Request);
end;
finally
InternetCloseHandle(InetConnect);
end;
finally
InternetCloseHandle(InetRoot);
end;
end;

Related

SoapUI testing: remove quotation marks from session ID

So, I am new to SoapUI, and working with API's in general, but I am trying to set up an automated test for a REST API in SoapUI (the freeware version).
The first call I make returns a session ID in JSON, which is placed between quotation markslike: "session ID goes here". This key is needed, without quotation marks, in the next API call. I use SOAPUI's "Property Transfer Teststep", and this is working well, apart from the quotationmarks which are still around the session ID, resulting in an error responce by the subsequent call.
Any idea how I can remove the quotation marks? Ive been reading up/Googling on Xpath and JSONPath, which are some of the coding languages I can use in the screen, but I cant see how to use this to remove said quotation marks.
Your help would be greatly appreciated!!
Full RAW Response:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: application/json; charset=utf-8 Expires: -1 Server: Microsoft-IIS/8.5 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Tue, 02 May 2017 18:31:48 GMT Content-Length: 38 "48d45ba2-4549-41be-8b31-e85b3c738a03"
you say that the message is returned as "48d45ba2-4549-41be-8b31-e85b3c738a03". Although the message says it is json, that does not mean that SoapUI will interprete it as valid json. Valid JSON like in the question referred to in another answer, starts and ends with curly brackets. Also it should have a key and value pair. Like so:
{
"sessionId":"48d45ba2-4549-41be-8b31-e85b3c738a03"
}
In that case the transfer $.sessionId would yield 48d45ba2-4549-41be-8b31-e85b3c738a03(without quotation marks), and not "48d45ba2-4549-41be-8b31-e85b3c738a03" (with quotation marks).
In attachment there is a project with a mock. It has got one call. If you open the project, you have to launch the mock by clicking play, then you can execute the test case. - https://www.dropbox.com/s/rsgc9q1g45jze5z/StackOverflow_43745255_QuestionQuotationMarks.xml?dl=0. You can save this as XML, then you can open it with SoapUI.
You will see a property transfer step. It has one step that is passed. Then one where you transfer the value without any paramter. It will transfer the message in full. Including the quotation marks.
The sencond transfer is '$'. For a valid json, this would render the same result as for the property transfer without any parameter because '$' represents the root. At least that is how I understand it.
Included you will also find a script:
response = context.testCase.getTestStepAt(0).testRequest.response.getResponseContent()
assert response == '"48d45ba2-4549-41be-8b31-e85b3c738a03"'
stripResponse = response.replace("\"", "")
assert stripResponse == '48d45ba2-4549-41be-8b31-e85b3c738a03'
The stripResponse is the response where the quotation marks are stripped away. You could then proceed to assign this variable to a property of choice, or inject it directly in the headers of a next step.
Sometimes scripting is the way to go.

WebAPI HttpResponse Message

For WebAPI2 Action results, HTTPResponseMessage is used as one of the return type and Request.CreateResponse is used to return the message.
Request.CreateResponse is handy when we want to return single instance of the model but if we want to return multiple rows from the “model”, there is no overload method for Request.CreateResponse or Request.CreateResponse which supports it(as far as I read). If someone could post the sample, it would be great
Also, I have few other queries.
• Why we have to go for HttpResponseMessage rather than IQueryable or Model return type?
• What is the difference between Request.CreateResponse and Request.CreateResponse , as we are able to return a single instance of the model using both methods. How we can choose one among the two?
You can make the return type of your action method be any serializable data. Content negotiation and formatters will turn the returned value into an HTTP response for you.
From Action Results in Web API 2:
Other Return Types
For all other return types, Web API uses a media formatter to serialize the return value. Web API writes the serialized value into the response body. The response status code is 200 (OK).
public class ProductsController : ApiController
{
public IEnumerable<Product> Get()
{
return GetAllProductsFromDB();
}
}
A disadvantage of this approach is that you cannot directly return an error code, such as 404. However, you can throw an HttpResponseException for error codes. For more information, see Exception Handling in ASP.NET Web API.
Web API uses the Accept header in the request to choose the formatter. For more information, see Content Negotiation.
Example request:
GET http://localhost/api/products HTTP/1.1
User-Agent: Fiddler
Host: localhost:24127
Accept: application/json
Example response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
Date: Mon, 27 Jan 2014 08:53:35 GMT
Content-Length: 56
[{"Id":1,"Name":"Yo-yo","Category":"Toys","Price":6.95}]

How to get HTTP status code from WinHttp request?

This page on msdn contains definitions of HTTP status codes presumably used in WinHTTP. Is there a way to retrieve HTTP status code from request made in WinHttp?
The only way I've found to get to response text, is to call WinHttpQueryHeaders, which returns HTTP response like this:
HTTP/1.1 404 Not Found
Date: Wed, 28 May 2014 08:20:29 GMT
Content-Length: 0
Server: Microsoft-HTTPAPI/2.0
Do I have to parse this string by myself to get status code, or is there some way already provided by WinHttp to do this?
Use this to read http status code (hRequest - handle of the request).
DWORD dwStatusCode = 0;
DWORD dwSize = sizeof(dwStatusCode);
WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
WINHTTP_HEADER_NAME_BY_INDEX,
&dwStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX);

WCF OData patching an entity set

Is it possible in update multiple entites based on a filter query in a batch request?
As an example of what I'm trying to achieve, say I want to update all product categories from foo to bar in one request to an OData endpoint, is there something like this that would work:
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: multipart/mixed; boundary=changeset_fa7b-4aa9-a01f
GET /api/products?$filter=category eq 'foo' HTTP/1.1
Accept:application/json
Content-ID: 1
--changeset_fa7b-4aa9-a01f
Content-Type: application/http
Content-Transfer-Encoding: binary
PATCH $1 HTTP/1.1
Accept: application/json
Content-Type: application/json;odata=verbose
{"category":"bar"}
--changeset_fa7b-4aa9-a01f--
--batch_36522ad7-fc75-4b56-8c71-56071383e77b--
I'm afraid the answer is no. There's no support for that in the protocol. And even if you remove the filtering from the question, trying to update all entities in the entity set so that they will have a same new value, the answer is still no.
You could probably do this yourself. Like,
Get /service.svc/MyEntitySet
and for every entity you get back, send a PATCH to update it individually.
In addition, if this kind of operation is going to be done frequently, the service author could write a specific service operation or action to do this on the server side. For example, write something called "ClearAllNames", and a user could invoke that, and the server would go through every entity and clear its name field.

Problems with Delphi Rest Client talking to C# Rest server

I am writing a REST WCF Service, and have it working for connections from a C# client, but am having issues with connecting via a Delphi 2009 client. The problem I have is specifically with a PUT request, which looks (for the moment) as below. It expects an XML request, containing the document's objects.
[WebInvoke(UriTemplate = "Document/{id}", Method = "PUT", RequestFormat=WebMessageFormat.Xml)]
public void UpdateDocument (string id, Document document)
{
Document doc = document;
// this should update or something!
Console.WriteLine(doc.Id);
}
When I try and call this via my Delphi client (as shown below), I get a 'Bad Request'. Oddly if I send an empty document, the request is received, but obviously has no data.
...
msg := '<?xml version="1.0"?>' +
'<Document>' +
'<Id>123456788888</Id>' +
'</Document>';
XMLDocument1.LoadFromXML(msg);
xmlStream := TMemoryStream.Create;
idHttp1.Request.ContentType := 'application/xml';
XMLDocument1.SaveToStream(xmlStream);
url := 'http://localhost:50435/service1/Document/12345678';
result := idHttp1.Put(url, xmlStream);
ShowMessage (result);
...
Any ideas, as I am a bit lost now!
Thanks
The mapping of the URI to server method is not correct. According to default mapping a PUT request will invoke AcceptDocument method, and a POST request will invoke UpdateDocument method.
http://docwiki.embarcadero.com/RADStudio/en/REST
Also passing a TStream as parameter is also possibility for difficulties. Is it possible for you to use JSON? I am not sure Delphi 2009 has support for JSON though.
Edit:
quote from Delphi documentation:
by default, a prefix of 'update' is assigned to any method invoked
with POST. Similarly, a prefix of 'cancel' is used for DELETE
requests, and a prefix of 'accept' is used for PUT requests. This
prefixing can be avoided by putting quotation marks around the method
name
Above quote applies to Delphi. Maybe also for WCF.
As per my comment above, installing Fiddler made me look at the actual page that the webservice outputs, this helpfully has example XML and json structures. I was missing the namespace for the object, so I guess the WCF end didn't know what to translate, changing the message to the following made it work:
msg := '<?xml version="1.0"?>' +
'<Document xmlns="http://schemas.datacontract.org/2004/07/Contracts.Contracts">' +
'<Id>123456788888</Id>' +
'</Document>';