Being able to import and use services provided by other applications, be they home or third party built, is an essential aspect of Web application development. It is also one of the most fundamental tenets of a service oriented architecture. While other topics in this documentation focus on the creation of Web Services, this topic will focus exclusively on how they can be used from a Morfik application.
Importing an External Web Service
Morfik makes using Web Services which are external to your current application, very easy. The only thing you need to start, is to have the WSDL file of the service you wish to use. For the sake of simplicity, I have chosen to import the WSDL file which is generated by a very simple math sample, in this topic. In Figure 1 you can see the Web Services option, in the Home tab of the riboon, when in the Project View of the Morfik development environment.
|
| Figure 1 Import Web Services menu option. |
This wizard makes it extremely easy for you to import any web service you want (provided you have access to its WSDL definition file), into your project.
Once the wizard is started, it will ask for the WSDL file that describes the service to be imported, as can be seen in Figure 2.
|
| Figure 2 Dialog for selecting the WSDL file to be imported. |
Once you have selected the WSDL file the wizard will display all the methods found in the service description, with their respective parameters, as shown in Figure 3.
|
| Figure 3 Methods (with parameters) available from the selected service. |
Next you will be asked if you will want to invoke the imported methods directly from the browser. If the answer to that is yes and the service you are importing will not be running under the same domain name as the application you are coding, you should choose the option that enables the usage of a server side proxy. This proxy is handled automatically by the Morfik Framework and will allow you to code your application as if you were accessing these 3rd party services as if they were running on your servers, despite the browser security restrictions.
|
| Figure 4 Browser code generation and its options. |
After you have completed the Import Web Service wizard, the IDE will have generated a dual module with the classes required to correctly call out to the imported methods in as easy a manner as possible from both the browser and server sides of your application. You can see the code for the server side portion of this module for these methods in Listing 1, and the browser side portion in Listing 2.
Listing 1 – Code for the automatically generated interface to the imported services
FX Code
Unit MathTestService; Interface Uses SystemClasses, SystemSerialiser, SystemXml; Type TMathTestServiceSoapIntf = Class(TSoapHttpClient) Procedure MathProcessor (operand1 : double; operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint); Virtual; Procedure MathProcessor2(Operand1 : double; Operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint); Virtual; End; Implementation {.................... MathTestServiceSoapIntf ....................} Procedure TMathTestServiceSoapIntf.MathProcessor(operand1 : double; operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint); Begin BeginInvoke('http://localhost:9119/?cls=soap', 'MathProcessor xmlns="http://tempuri.org/"', 'MathProcessorResponse xmlns="http://tempuri.org/"', 'MathProcessor',ssDocumentWrapped); Try Try RequestBody.WriteDouble('operand1 xsi:type="xsd:double"', operand1); RequestBody.WriteDouble('operand2 xsi:type="xsd:double"', operand2); RequestBody.Writestring('theOperator xsi:type="xsd:string"', theOperator); Invoke(); ReplyBody.ReadDouble('theResult xsi:type="xsd:double"', theResult); ReplyBody.Readinteger('Status xsi:type="xsd:int"', Status_1); Except Raise; End Finally EndInvoke(); End End; Procedure TMathTestServiceSoapIntf.MathProcessor2(Operand1 : double; Operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint); Begin BeginInvoke('http://localhost:9119/?cls=soap', 'MathProcessor2 xmlns="http://tempuri.org/"', 'MathProcessor2Response xmlns="http://tempuri.org/"', 'MathProcessor2',ssDocumentWrapped); Try Try RequestBody.WriteDouble('Operand1 xsi:type="xsd:double"', Operand1); RequestBody.WriteDouble('Operand2 xsi:type="xsd:double"', Operand2); RequestBody.Writestring('theOperator xsi:type="xsd:string"', theOperator); Invoke(); ReplyBody.ReadDouble('theResult xsi:type="xsd:double"', theResult); ReplyBody.Readinteger('Status xsi:type="xsd:int"', Status_1); Except Raise; End Finally EndInvoke(); End End; Begin End.
| BX Code |
|---|
/* %MA STATIC */ Imports SystemClasses Imports SystemSerialiser Imports SystemXML Namespace MathTestService Public Class TMathTestServiceSoapIntf Inherits TSoapHttpClient Public Overridable Sub MathProcessor(operand1 As Double, operand2 As Double, theOperator As String, ByRef theResult As Double, ByRef Status_1 As Longint) BeginInvoke("http://localhost:9119/?cls=soap", "MathProcessor xmlns=""http://tempuri.org/""", "MathProcessorResponse xmlns=""http://tempuri.org/""", "MathProcessor", ssDocumentWrapped) Try Try RequestBody.WriteDouble("operand1 xsi:type=""xsd:double""", operand1) RequestBody.WriteDouble("operand2 xsi:type=""xsd:double""", operand2) RequestBody.WriteString("theOperator xsi:type=""xsd:string""", theOperator) Invoke() ReplyBody.ReadDouble("theResult xsi:type=""xsd:double""", theResult) ReplyBody.ReadInteger("Status xsi:type=""xsd:int""", Status_1) Catch Throw End Try Finally EndInvoke() End Try End Sub Public Overridable Sub MathProcessor2(Operand1 As Double, Operand2 As Double, theOperator As String, ByRef theResult As Double, ByRef Status_1 As Longint) BeginInvoke("http://localhost:9119/?cls=soap", "MathProcessor2 xmlns=""http://tempuri.org/""", "MathProcessor2Response xmlns=""http://tempuri.org/""", "MathProcessor2", ssDocumentWrapped) Try Try RequestBody.WriteDouble("Operand1 xsi:type=""xsd:double""", Operand1) RequestBody.WriteDouble("Operand2 xsi:type=""xsd:double""", Operand2) RequestBody.WriteString("theOperator xsi:type=""xsd:string""", theOperator) Invoke() ReplyBody.ReadDouble("theResult xsi:type=""xsd:double""", theResult) ReplyBody.ReadInteger("Status xsi:type=""xsd:int""", Status_1) Catch Throw End Try Finally EndInvoke() End Try End Sub End Class End Namespace |
| CX Code |
|---|
/* $MA STATIC */ imports SystemClasses; imports SystemSerialiser; imports SystemXML; namespace MathTestService { public class TMathTestServiceSoapIntf : TSoapHttpClient { public virtual void MathProcessor(Double operand1, Double operand2, String theOperator, ref Double theResult, ref Longint Status_1) { BeginInvoke("http://localhost:9119/?cls=soap", "MathProcessor xmlns=\"http://tempuri.org/\"", "MathProcessorResponse xmlns=\"http://tempuri.org/\"", "MathProcessor", ssDocumentWrapped); try { try { RequestBody.WriteDouble("operand1 xsi:type=\"xsd:double\"", operand1); RequestBody.WriteDouble("operand2 xsi:type=\"xsd:double\"", operand2); RequestBody.WriteString("theOperator xsi:type=\"xsd:string\"", theOperator); Invoke(); ReplyBody.ReadDouble("theResult xsi:type=\"xsd:double\"", theResult); ReplyBody.ReadInteger("Status xsi:type=\"xsd:int\"", Status_1); } catch { throw; } } finally { EndInvoke(); } } public virtual void MathProcessor2(Double Operand1, Double Operand2, String theOperator, ref Double theResult, ref Longint Status_1) { BeginInvoke("http://localhost:9119/?cls=soap", "MathProcessor2 xmlns=\"http://tempuri.org/\"", "MathProcessor2Response xmlns=\"http://tempuri.org/\"", "MathProcessor2", ssDocumentWrapped); try { try { RequestBody.WriteDouble("Operand1 xsi:type=\"xsd:double\"", Operand1); RequestBody.WriteDouble("Operand2 xsi:type=\"xsd:double\"", Operand2); RequestBody.WriteString("theOperator xsi:type=\"xsd:string\"", theOperator); Invoke(); ReplyBody.ReadDouble("theResult xsi:type=\"xsd:double\"", theResult); ReplyBody.ReadInteger("Status xsi:type=\"xsd:int\"", Status_1); } catch { throw; } } finally { EndInvoke(); } } } } |
This unit (Listing 1) has very little auxiliary and support code being primarily a wrapper around the necessary information serialization code. From that listing what should mainly interest the programmer, who is a user (consumer) of the web service, is a class that offers two methods, each tied to a "function" (a web method, by its own right) of the service. You can see this classes interface below:
FX Code
TMathTestServiceSoapIntf = Class(TSoapHttpClient) Procedure MathProcessor (operand1 : double; operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint); Virtual; Procedure MathProcessor2(Operand1 : double; Operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint); Virtual; End;
| BX Code |
|---|
Public Class TMathTestServiceSoapIntf Inherits TSoapHttpClient Public Overridable Sub MathProcessor(operand1 As Double, operand2 As Double, theOperator As String, ByRef theResult As Double, ByRef Status_1 As Longint) End Sub Public Overridable Sub MathProcessor2(Operand1 As Double, Operand2 As Double, theOperator As String, ByRef theResult As Double, ByRef Status_1 As Longint) End Sub End Class |
| CX Code |
|---|
public class TMathTestServiceSoapIntf : TSoapHttpClient { public virtual void MathProcessor(Double operand1, Double operand2, String theOperator, ref Double theResult, ref Longint Status_1) { } public virtual void MathProcessor2(Double Operand1, Double Operand2, String theOperator, ref Double theResult, ref Longint Status_1) { } } |
Careful observation of this code will undoubtedly reveal that this class’ methods are, in fact, an exact representation of what WebMethods we, originally, added to our application
Listing 2 – Code for the automatically generated browser side interface to the imported services
FX Code
Unit MathTestService; ['AutoSynchronize=None']; Interface Uses SystemUtilities, SystemClasses, SystemRPC, SystemCatalog, SystemWebMethod; Type TMathTestServiceMethod = Class(TSoapClient) Constructor Create(aMethodName : String); End; TMathProcessor = Class(TMathTestServiceMethod) operand1 : double; operand2 : double; theOperator : string; theResult : double; Status_1 : longint; Constructor Create; procedure Execute; ['AutoSynchronize=Manual']; Override; End; TMathProcessor2 = Class(TMathTestServiceMethod) Operand1 : double; Operand2 : double; theOperator : string; theResult : double; Status_1 : longint; Constructor Create; procedure Execute; ['AutoSynchronize=Manual']; Override; End; Implementation {.................... MathTestServiceSoapIntf ....................} Constructor TMathTestServiceMethod.Create(aMethodName : String); Begin Inherited Create(aMethodName); UseProxyServer := True; ServiceURL := 'http://localhost:9119/?cls=soap'; End; Constructor TMathProcessor.Create; Begin Inherited Create('MathProcessor'); SoapAction := 'MathProcessor'; End; Procedure TMathProcessor.Execute; Begin With Self Do Begin Self.Bind('operand1',@operand1); Self.Bind('operand2',@operand2); Self.Bind('theOperator',@theOperator); Self.Bind('theResult',@theResult); Self.Bind('Status',@Status_1); End; Inherited Execute; End; Constructor TMathProcessor2.Create; Begin Inherited Create('MathProcessor2'); SoapAction := 'MathProcessor2'; End; Procedure TMathProcessor2.Execute; Begin With Self Do Begin Self.Bind('Operand1',@Operand1); Self.Bind('Operand2',@Operand2); Self.Bind('theOperator',@theOperator); Self.Bind('theResult',@theResult); Self.Bind('Status',@Status_1); End; Inherited Execute; End; Function MathTestService_CreateList(Name : String) : Pointer; Begin Result := Nil; End; Procedure MathTestServiceSRLZRegister; Begin With TSerializableMethodInfo.Create('MathProcessor') Do Begin RequestNameSpace := 'http://tempuri.org/'; RequestNameSpaceAlias := ''; AddField('operand1','double',ptIn); AddField('operand2','double',ptIn); AddField('theOperator','string',ptIn); AddField('theResult','double',ptOut); AddField('Status','longint',ptOut); End; With TSerializableMethodInfo.Create('MathProcessor2') Do Begin RequestNameSpace := 'http://tempuri.org/'; RequestNameSpaceAlias := ''; AddField('Operand1','double',ptIn); AddField('Operand2','double',ptIn); AddField('theOperator','string',ptIn); AddField('theResult','double',ptOut); AddField('Status','longint',ptOut); End; End; Begin MathTestServiceSRLZRegister; End.
| BX Code |
|---|
/* %MA STATIC */ Imports SystemUtilities Imports SystemClasses Imports SystemRPC Imports SystemCatalog Imports SystemWebMethod Namespace MathTestService Public Class TMathTestServiceMethod Inherits TSoapClient Public Sub New(aMethodName As String) MyBase.New(aMethodName) UseProxyServer = true ServiceURL = "http://localhost:9119/?cls=soap" End Sub End Class Public Class TMathProcessor Inherits TMathTestServiceMethod Public operand1 As Double Public operand2 As Double Public theOperator As String Public theResult As Double Public Status_1 As Longint Public Sub New MyBase.New("MathProcessor") SoapAction = "MathProcessor" End Sub Public Overrides Sub Execute :{"AutoSynchronize=Manual"} With Me Me.Bind("operand1", Ref operand1) Me.Bind("operand2", Ref operand2) Me.Bind("theOperator", Ref theOperator) Me.Bind("theResult", Ref theResult) Me.Bind("Status", Ref Status_1) End With MyBase.Execute() End Sub End Class Public Class TMathProcessor2 Inherits TMathTestServiceMethod Public Operand1 As Double Public Operand2 As Double Public theOperator As String Public theResult As Double Public Status_1 As Longint Public Sub New MyBase.New("MathProcessor2") SoapAction = "MathProcessor2" End Sub Public Overrides Sub Execute :{"AutoSynchronize=Manual"} With Me Me.Bind("Operand1", Ref Operand1) Me.Bind("Operand2", Ref Operand2) Me.Bind("theOperator", Ref theOperator) Me.Bind("theResult", Ref theResult) Me.Bind("Status", Ref Status_1) End With MyBase.Execute() End Sub End Class Private Function MathTestService_CreateList(Name As String) As Pointer result = Nothing End Function Private Sub MathTestServiceSRLZRegister With New TSerializableMethodInfo("MathProcessor") RequestNameSpace = "http://tempuri.org/" RequestNameSpaceAlias = "" AddField("operand1", "double", ptin) AddField("operand2", "double", ptin) AddField("theOperator", "String", ptin) AddField("theResult", "double", ptout) AddField("Status", "longint", ptout) End With With New TSerializableMethodInfo("MathProcessor2") RequestNameSpace = "http://tempuri.org/" RequestNameSpaceAlias = "" AddField("Operand1", "double", ptin) AddField("Operand2", "double", ptin) AddField("theOperator", "String", ptin) AddField("theResult", "double", ptout) AddField("Status", "longint", ptout) End With End Sub Initialization MathTestServiceSRLZRegister() End Initialization End Namespace |
| CX Code |
|---|
/* $MA STATIC */ imports SystemUtilities; imports SystemClasses; imports SystemRPC; imports SystemCatalog; imports SystemWebMethod; namespace MathTestService { public class TMathTestServiceMethod : TSoapClient { public TMathTestServiceMethod(String aMethodName) { base.Create(aMethodName); UseProxyServer = true; ServiceURL = "http://localhost:9119/?cls=soap"; } } public class TMathProcessor : TMathTestServiceMethod { public Double operand1; public Double operand2; public String theOperator; public Double theResult; public Longint Status_1; public TMathProcessor() { base.Create("MathProcessor"); SoapAction = "MathProcessor"; } public override void Execute() ["AutoSynchronize=Manual"] { with(this) { this.Bind("operand1", &operand1); this.Bind("operand2", &operand2); this.Bind("theOperator", &theOperator); this.Bind("theResult", &theResult); this.Bind("Status", &Status_1); } base.Execute(); } } public class TMathProcessor2 : TMathTestServiceMethod { public Double Operand1; public Double Operand2; public String theOperator; public Double theResult; public Longint Status_1; public TMathProcessor2() { base.Create("MathProcessor2"); SoapAction = "MathProcessor2"; } public override void Execute() ["AutoSynchronize=Manual"] { with(this) { this.Bind("Operand1", &Operand1); this.Bind("Operand2", &Operand2); this.Bind("theOperator", &theOperator); this.Bind("theResult", &theResult); this.Bind("Status", &Status_1); } base.Execute(); } } private Pointer MathTestService_CreateList(String Name) { result = null; } private void MathTestServiceSRLZRegister() { with(new TSerializableMethodInfo("MathProcessor")) { RequestNameSpace = "http://tempuri.org/"; RequestNameSpaceAlias = ""; AddField("operand1", "double", ptin); AddField("operand2", "double", ptin); AddField("theOperator", "String", ptin); AddField("theResult", "double", ptout); AddField("Status", "longint", ptout); } with(new TSerializableMethodInfo("MathProcessor2")) { RequestNameSpace = "http://tempuri.org/"; RequestNameSpaceAlias = ""; AddField("Operand1", "double", ptin); AddField("Operand2", "double", ptin); AddField("theOperator", "String", ptin); AddField("theResult", "double", ptout); AddField("Status", "longint", ptout); } } initialization { MathTestServiceSRLZRegister(); } } |
This module (Listing 2) has a good quantity of auxiliary and support code which is not of much interest to the user of services. From that listing what should mainly interest the programmer, who is a user (consumer) of the web service, are two classes that embody the services definition. Each class is tied to a "functionailty" (a web method, by its own right) of the service. You can see the interface for these classes below:
FX Code
TMathProcessor = Class(TMathTestServiceMethod) operand1 : double; operand2 : double; theOperator : string; theResult : double; Status_1 : longint; Constructor Create; procedure Execute; ['AutoSynchronize=Manual']; Override; End; TMathProcessor2 = Class(TMathTestServiceMethod) Operand1 : double; Operand2 : double; theOperator : string; theResult : double; Status_1 : longint; Constructor Create; procedure Execute; ['AutoSynchronize=Manual']; Override; End;
| BX Code |
|---|
Public Class TMathProcessor Inherits TMathTestServiceMethod Public operand1 As Double Public operand2 As Double Public theOperator As String Public theResult As Double Public Status_1 As Longint Public Sub New End Sub Public Overrides Sub Execute :{"AutoSynchronize=Manual"} End Sub End Class Public Class TMathProcessor2 Inherits TMathTestServiceMethod Public Operand1 As Double Public Operand2 As Double Public theOperator As String Public theResult As Double Public Status_1 As Longint Public Sub New End Sub Public Overrides Sub Execute :{"AutoSynchronize=Manual"} End Sub End Class |
| CX Code |
|---|
public class TMathProcessor : TMathTestServiceMethod { public Double operand1; public Double operand2; public String theOperator; public Double theResult; public Longint Status_1; public TMathProcessor() { } public override void Execute() ["AutoSynchronize=Manual"] { } } public class TMathProcessor2 : TMathTestServiceMethod { public Double Operand1; public Double Operand2; public String theOperator; public Double theResult; public Longint Status_1; public TMathProcessor2() { } public override void Execute() ["AutoSynchronize=Manual"] { } } |
Calling a Imported Web Service
Once the Web Service has been imported into your project, calling it up is not difficult, though calling it from the Server or Browser portions of your application work differently.
Using a Web Service from the Server
If you create a version of our WebMethod test class, renaming the WebMethod as MathRequester, you can import the .WSDL file from the project where those web services are declared and change the Execute method of the MathRequester version of the Web Method to call the original Web Service in its first implementation. The main difference between this new application and the original one is that the MathRequester WebMethod does not process the operations; it forwards the request to the original application, now running as a service provider.
Only the name of the WebMethod was changed and its server side code. The code you see in Listing 3 is that of the Server side of the MathRequester Web Method.
Listing 3 – Server side code calling out to the imported Web Service.
FX Code
Unit MathRequester; Interface Type MathRequester=Class(WebMethod) Operand1 : Double; Operand2 : Double; theOperator : String; theResult : Double; Status : Integer; Private { Private declarations } Public { Public declarations } Procedure Execute; override; End; ['WSPublished=False']; Implementation Uses MathTestService; Procedure MathRequester.Execute; Var MathInt: TMathTestServiceSoapIntf; Begin MathInt := TMathTestServiceSoapIntf.Create; Try MathInt.MathProcessor (Operand1, Operand2, theOperator, theResult, Status); Finally MathInt.Free; End; End; End.
| BX Code |
|---|
/* %MA STATIC */ Imports SystemWebMethod Imports MathTestService Namespace MathRequester Public Class MathRequester Inherits WebMethod Public Operand1 As Double Public Operand2 As Double Public theOperator As String Public theResult As Double Public Status As Integer ' Public declarations Public Overrides Sub Execute Dim MathInt As TMathTestServiceSoapIntf MathInt = New TMathTestServiceSoapIntf() Try MathInt.MathProcessor(Operand1, Operand2, theOperator, theResult, Status) Finally MathInt.Free() End Try End Sub End Class :{"WSPublished=False"} End Namespace |
| CX Code |
|---|
/* $MA STATIC */ imports SystemWebMethod; imports MathTestService; namespace MathRequester { public class MathRequester : WebMethod { public Double Operand1; public Double Operand2; public String theOperator; public Double theResult; public Integer Status; //' Public declarations public override void Execute() { TMathTestServiceSoapIntf MathInt; MathInt = new TMathTestServiceSoapIntf(); try { MathInt.MathProcessor(Operand1, Operand2, theOperator, theResult, Status); } finally { MathInt.Free(); } } } ["WSPublished=False"] } |
You will notice that this service (MathRequester) has the same parameters as the remote target service (MathProcessor). This is necessary since the information is just going through this service, but it also makes it quite easy to handle the remote call and the return of the result (out) values to the browser side of your applications.
Using a Web Service from the Browser
As mentioned in the first part of this post, Morfik makes it possible for the developer to write client side code that makes direct references to a Web Service, even if it is published by a 3rd party. This is handled by the Morfik Framework that implements a transparent proxy on the server side portion of your application.
This leads to greater simplicity in writing applications that rely on such services as it is not necessary to create a new layer of web method code to transfer execution to the server and then relay the response. All this is handled transparently by the Morfik Framework without the need of any additional coding.
Listing 4 shows an example of what direct browser access to our MathProcessor sample Web Method would look like.
FX Code
Unit Content; Interface Uses SystemRPC; Type Content=Class(Form) TextLabel1 : TextLabel; TextLabel2 : TextLabel; btnExecuteMathOp : Button; Op1Edit : TextEdit; Op2Edit : TextEdit; Procedure btnExecuteMathOpClick(Event: TDOMEvent); Message; Private { Private declarations } Procedure GetMathOpResult(SoapClient : TSoapClient); Public { Public declarations } End; Implementation Uses MathTestService; Procedure Content.GetMathOpResult(SoapClient : TSoapClient); Var MathOp: TMathProcessor; Begin MathOp := TMathProcessor(SoapClient); Try TextLabel1.Caption := MathOp.theResult.ToString; Finally MathOp.Free; End; End; Procedure Content.btnExecuteMathOpClick(Event: TDOMEvent); Var MathOp: TMathProcessor; Begin MathOp := TMathProcessor.Create; MathOp.operand1 := Op1Edit.Text.ToInteger; MathOp.operand2 := Op2Edit.Text.ToInteger; MathOp.theOperator := 'ADD'; MathOp.OnWebMethodReturn := @GetMathOpResult; MathOp.Execute; End; End.
| BX Code |
|---|
/* %MA DYNAMIC */ Imports SystemRPC Using MathTestService Namespace Content Public Class Content Inherits Form Published TextLabel1 As TextLabel Published TextLabel2 As TextLabel Published btnExecuteMathOp As Button Published Op1Edit As TextEdit Published Op2Edit As TextEdit ' Private declarations Private Sub GetMathOpResult(SoapClient As TSoapClient) Dim MathOp As TMathProcessor MathOp = Ctype(SoapClient, TMathProcessor) Try TextLabel1.Caption = MathOp.theResult.ToString() Finally MathOp.Free() End Try End Sub Published Message Sub btnExecuteMathOpClick(Event As TDOMEvent) Dim MathOp As TMathProcessor MathOp = New TMathProcessor() MathOp.operand1 = Op1Edit.Text.ToInteger() MathOp.operand2 = Op2Edit.Text.ToInteger() MathOp.theOperator = "ADD" MathOp.OnWebMethodReturn = Ref GetMathOpResult MathOp.Execute() End Sub End Class End Namespace |
| CX Code |
|---|
/* $MA DYNAMIC */ imports SystemRPC; using MathTestService; namespace Content { public class Content : Form { published TextLabel TextLabel1; published TextLabel TextLabel2; published Button btnExecuteMathOp; published TextEdit Op1Edit; published TextEdit Op2Edit; //' Private declarations private void GetMathOpResult(TSoapClient SoapClient) { TMathProcessor MathOp; MathOp = (TMathProcessor)(SoapClient); try { TextLabel1.Caption = MathOp.theResult.ToString(); } finally { MathOp.Free(); } } published message void btnExecuteMathOpClick(TDOMEvent Event) { TMathProcessor MathOp; MathOp = new TMathProcessor(); MathOp.operand1 = Op1Edit.Text.ToInteger(); MathOp.operand2 = Op2Edit.Text.ToInteger(); MathOp.theOperator = "ADD"; MathOp.OnWebMethodReturn = &GetMathOpResult; MathOp.Execute(); } } } |
The code that is presented in Listing 4 has two methods that exemplify the fundamentals of Web Service usage from the browser portion of a Morfik application. The first method is the btnExecuteMathOpClick method which is associated to the OnClick event of a button so that the user can directly trigger the execution of the request. This method instantiates the appropriate WebMethod class and sets its parameters before calling its Execute method.
Event though the Execute method will immediately return, it is important to remember that the actual Web Service call is asynchronous and will not return immediately. In order to receive a notification that the underlying Web Service being requested has returned the OnWebMethodReturn property of the Web Method that was instantiated is set to point to another method that takes a TSoapClient parameter.
In the case show in listing 4 this is the GetMathOpResult method. Inside this method the parameter is typecast into the type of the Web Method that was originally invoked and after its output parameters are read, the corresponding object is freed.
Related Topics
- What are Web Services and why do I need to use them?
- Understanding the way Web Services are used in Morfik
- Creating Web Methods and using them in your application
- Non-visual Web Methods

