From: Marcus S. <mar...@gm...> - 2002-05-27 22:15:29
|
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 |