Hello,
I had a closer look to the WebService/SOAP functionality of the
.NET-Framework today.
1. CLIENT SIDE
On the client side, all Web Service calls seem to be implemented as
derivations of a class called "SoapHttpClientProtocol" (it's inside the
"System.Web.Services.Protocols" namespace).
So if a .NET application wants to communicate with a Web Service as a
client, it has to implement a proxy
class that does the actual invocations. Such a proxy class would look
something like this in C# (shortened):
[System.Web.Services.WebServiceBindingAttribute(Name="CTestServiceSoap",
Namespace="http://tempuri.org/")]
public class CTestService :
System.Web.Services.Protocols.SoapHttpClientProtocol
{
public CTestService()
{
// URL of the Web Service endpoint
this.Url = "http://localhost:180/services/01.test/TestService.asmx";
}
// Dispatched invokation of a WebService method that doesn't take any
arguments
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.o
rg/GetId",
RequestNamespace="http://tempuri.org/",
ResponseNamespace="http://tempuri.org/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string GetId()
{
object[] results = this.Invoke("GetId", new object[0]);
return ((string)(results[0]));
}
// Dispatched invokation of a WebService method that takes a string as an
argument
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.o
rg/SayHello",
RequestNamespace="http://tempuri.org/",
ResponseNamespace="http://tempuri.org/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string SayHello(string sName) {
object[] results = this.Invoke("SayHello", new object[] {sName} );
return ((string)(results[0]));
}
}
If you aren't familiar with the C# syntax I'll explain the main processes,
when an applications makes
use of this proxy class via the following code:
CTestService wsTestService = new CTestService(); // a new instance of the
proxy class is created
String sRes = CTestService.SayHello("World"); // the Web Service's
method "SayHello" is called
and the required
argument "World" is specified
MessageBox.Show(sRes); // The result of the
call is displayed
(At the moment, we're not interested in how the server implements the Web
Service)
Internally, when the CTestService proxy class is instantiated, the "Url"
property of the
overlaying "SoapHttpClientProtocol" class is set to the Web Service's
endpoint URL.
Then, when the proxy's method "SayHello()" is called, the proxy uses the
inherited "Invoke" method
to call the Web Service method with the supplied arguments. The value
returned by the
Web Service serves as the result of the function.
Since .NET allows the invokation of the "SoapHttpClientProtocol::Invoke"
method only
out of a class that inherits from "SoapHttpClientProtocol", we can't use the
methods
of "DotNetExec" at their present state, because
NETInvokeMethod(aSoapClient, "Invoke", ["SayHello", ["World"]])
or something like this would produce an exception :-(
Has someone discovered another way to invoke Web Services from within the
.NET framework ?
If not, we could extend the DotNetExec unit to that effect, that we
introduce a new
function like "NETInvokeWSMethod()" that causes the C#-part of DotNetExec
("DotNetExec.cs")
to internally create such a proxy class, invoke it and dispatch the return
value.
However, that's not a elegant way to solve the problem, so if anyone has a
better method
or an idea, PLEASE tell us :>
2. SERVER SIDE
In .NET, you're supposed to implement Web Services as ASP.NET pages. These
ASP.NET
Web Services can be written in any .NET-enabled language (i.e. a language an
implementation of the "System.CodeDom.Compiler.CodeDomProvider" class exists
for
- a quite BIG effort to implement, so Delphi.NET goes an other way), like
VB.NET,
C# or JScript.NET. Such an ASP.NET document can be very simple like this C#
example:
<%@ WebService Language="C#" Class="CTestService" %>
using System;
using System.Web.Services;
public class CTestService
{
[WebMethod]
public String GetId()
{
return "TestWebService";
}
[WebMethod(Description="Sagt servus")]
public String SayHello(String sName)
{
return "Hello " + sName + " !";
}
}
Such an .asmx-document (that's the default suffix for an ASP.NET-WebService)
needs the
Internet Information Services (IIS) 5.0 or higher to run.
So if we want to provide server-sided Web Services functionality in
Delphi.NET (and don't
want to implement the mentioned "System.CodeDom.Compiler.CodeDomProvider" -
anyone
looked at it ? Gosh! ;D ) we must again find an "indirect" way.
One possibiliy would be to write a (more or less) little utility that
creates wrapper
ASP.NET files from an DLL (that can be implemented with Delphi i.a.). That
could
look like (*untested*):
<%@ WebService Language="C#" Class="CTestService" %>
using System;
using System.Web.Services;
public class CTestService
{
[WebMethod]
[DllImport("Delphi.dll", EntryPoint="GetId", ExactSpelling=true)]
public static extern String GetId();
[WebMethod]
[DllImport("Delphi.dll", EntryPoint="SayHello", ExactSpelling=true)]
public static extern String SayHello(String sName);
}
If no one can think of a better solution for this problem - is there
someone who would be interested in writing such a tool ?
A problem could be that one can't determine the argument list of a DLL
function or do I err ?
In this case we could dispatch the Web Service calls to a COM object instead
to a DLL.
These were just some things I discovered ... If some passages were unclear
please object to
them :-)
cu
marcus
|