Fibonacci Proxy The WSDL describes the Web Service and because the WSDL is so complete, we can create a proxy class using tools that are capable of reading the WSDL.. For example, we ca
Trang 1Now that we've had a foundation in UDDI and WSDL, let's shift our discussion towards actually using WSDL to build a proxy class that is capable of calling a Web Service
Building Web Service Proxies
A proxy does work on behalf of others A good example is proxy web server software Users configure their web browser
to use a proxy server and make requests for Internet resources, such as http://msdn.microsoft.com/ to the proxy The proxy then makes a request on the behalf of the browser to the requested URL
We can use proxy classes to represent the Web Service we want to call
In the previous chapter we created a class named Fibonacci, that supports a single method called GetSeqNumber We compiled the class into a NET assembly and deployed it to an ASP.NET application's \bin directory (on the server) We can use this assembly as both a Web Service and a local class inside an ASP.NET page For example, we could write the following ASP.NET page (using VB NET):
<script runat="server">
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim fibonacci As New Fibonacci()
result.Text = Fibonacci.GetSeqNumber(5)
End Sub
</script>
Index of 5 in the Fibonacci Series is:
<asp:literal id="result" runat="server"/>
However, we've also implemented this class as a Web Service, which means that we also have the ability to call the GetSeqNumber method via SOAP over a network
The question is, can we expect applications that wish to use our Fibonacci Web Service to work with the raw SOAP messages (the HTTP and XML) directly? Probably not Consumers of our Web Service should not have to formulate their
Trang 2own XML messages, and then encapsulate those messages in HTTP in order to send them to the appropriate destination The same is true for receiving messages What consumers should use is a proxy representation of the Web Service
Fibonacci Proxy
The WSDL describes the Web Service and because the WSDL is so complete, we can create a proxy class using tools that are capable of reading the WSDL For example, we can build a proxy class for our Fibonacci Web Service that will have a class named Fibonacci and a method named GetSeqNumber
The proxy class does not contain the actual implementation (the code that calculates the sequence number), since this is not described in the WSDL The implementation still resides within the Web Service we're calling However, the proxy does look and feel the same It has the same class name and same method name/parameters as a local Fibonacci class, but the methods wrap calls to the remote Fibonacci Web Service For example, here's the VB NET pseudo-code for a proxy implementation of Fibonacci:
Public Class Fibonacci
Public Function GetSeqNumber(ByVal fibIndex As Integer) As Integer
Dim results() As Object = Me.Invoke("GetSeqNumber", _
New Object() {fibIndex})
Return CType(results(0),Integer)
Trang 3End Function
End Class
In this pseudo-code we have a class named Fibonacci, and a single function named GetSeqNumber
The proxy function name and parameters look identical to the Web Service implementation, but the actual
implementation (highlighted) is obviously different Here we have two lines of code The first line uses the Invoke() function to call the Web Service and return a result The second line uses the VB NET CType() function to cast the return data, results(0), to an Integer:
Public Function GetSeqNumber(ByVal fibIndex As Integer) As Integer
Dim results() As Object = Me.Invoke("GetSeqNumber", _
New Object() {fibIndex})
Return CType(results(0),Integer)
End Function
Let's expand this a little further Imagine if our Fibonacci Web Service was implemented on a server residing in New York, while the application that wished to call it was in Seattle Our Seattle application could examine the WSDL of the New York Fibonacci Web Service, and construct a proxy class similar to the example above The application could then write a ASP.NET page that, when requested, would use the local proxy to call the Fibonacci Web Service in New York The New York Web Service would then perform the work and return the result back to the application in Seattle that called it:
Trang 4The ASP.NET Page that uses the Fibonacci proxy might look as follows (written using VB NET):
' Seattle ASP.NET application
<script runat="server">
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim fibonacci As New Fibonacci()
lblResult = Fibonacci.GetSeqNumber(5)
End Sub
</script>
Index of 5 in the Fibonacci Series is:
<asp:label id="lblResult" runat="server"/>
To the Seattle developer who is coding the application, it appears as if Fibonacci is a local class, when in fact the class
is a proxy of the New York Web Service
Now that we know what a proxy is used for, let's talk about how can we automate its creation?
Trang 5Creating Proxy Classes
There are four ways to create proxies for Web Services:
Use Visual Studio NET and add a Web Reference to a new project
Use the command-line wsdl.exe utility available with the NET Framework SDK
Use the Microsoft SOAP toolkit
As long as the platform is capable of sending and receiving HTTP and is capable of parsing strings (or supports XML) you've got everything you need to communicate with a Web Service, so we could roll our own using the technology of our choice
Although all the examples in this chapter will use ASP.NET Web Services, the NET technology used to create the proxies could be applied to any Web Service so long as it uses SOAP
Because this book is about NET, we're only going to focus on the first two options for building proxies: Visual Stuido.NET and the wsdl.exe command-line tool The second option, using the command-line tool wsdl.exe, is applicable if you don't have Visual Studio NET However, using Visual Studio NET, is by far the easiest method available
Let's start by looking at how we build a proxy using Visual Studio NET After we use both Visual Studio NET and the command-line tool to build and use a proxy, we'll come back and examine the auto-generated proxy class in more detail For both examples we'll use the Fibonacci Web Service we created in the previous chapter
Visual Studio NET
If you've built an application using Visual Basic 6 you're probably familiar with the AddReference option, available from any VB project under Project|Add Reference, that allowed us to reference a component we wanted to include in our project
Including a reference allows us to early-bind to the object, instead of late binding Early binding simply allows us to know the data types at run-time/compile time, while late binding would force the code to determine the data types at run-time For example, late-bound code would be as follows (this code is written in Visual Basic 6 and so makes use of the Object data type):
Dim objAdo As Object
Set objAdo = CreateObject("ADODB.Connection")
With late-bound code we would treat an instance of ADODB.Connection as an Object type and VB would be responsible for calling the appropriate methods at run-time Late binding is expensive, and we want to avoid it where possible because
Trang 6the application needs to infer the appropriate data types to use at run-time
Instead of writing late-bound code, we could use the AddReference option in VB to add a reference at design time Our code would then become:
Dim objAdo As New ADODB.Connection
VB would treat objAdo as an instance of type ADODB.Connection at run-time
Visual Studio NET continues to support the concepts of early and late binding, as well as the Project | Add Reference
option However, we have a new option specifically designed for Web Services: Project | Add Web Reference
Add Web Reference
Just as we can early-bind to local classes, Visual Studio NET supports the capability to early-bind to Web Services
When we add a Web Reference to a Visual Studio NET project (the AddWebReference option is available to all Visual Studio NET projects and languages) VisualStudio.NET will do all the work required to connect to the Web Service, parse the WSDL, and it will generate a proxy class that we can use
Using the Fibonacci Web Service
Let's look at an example using our Fibonacci Web Service Before we can create the Web Reference we need to know the location of the WSDL for the Web Service we want to create the reference to For example, the address of the WSDL for the VB NET Fibonacci implementation of the ASP.NET Web Service on my server is
http://localhost/WebServices/Fibonacci_vb.asmx?WSDL
Next, let's create a new Visual Studio NET project Since this book is about ASP.NET, we'll create a new ASP.NET Web Application using Visual Basic NET as our language Once Visual Studio NET creates the new Web Application we're presented with a design page We can drag-and-drop elements onto this page For this example, we'll need a textbox, a label, and a button:
Trang 7We'll leave the names of each of these items the same, that is, TextBox1, Button1, and Label1 Now we're ready to add our Web Reference
We have two options, we can either select Project | Add Web Reference or we can right-click on the References in the
Solution Explorer and select Add Web Reference Both open the Add Web Reference dialog box:
Trang 8Within this dialog box we can browse services provided by UDDI (the link to Microsoft UDDI takes us to the Microsoft UDDI implementation), browse Web References on the local server (for Web Services we created with Visual Studio NET), or enter the address ourselves
Enter the address of our Fibonacci Web Service:
On the left-hand side of the Add Web Reference dialog we can view the WSDL Essentially what has happened is that Visual Studio NET fetched the WSDL from the location we specified and validated it The Add Reference button is now enabled and we are able to add a reference to the Web Service described by this WSDL to our current project (at which point Visual Studio NET will create a proxy)
Go ahead and press Add Reference Visual Studio NET will quietly create a new section in our Solution Explorer entitled
Web References Behind the scenes Visual Studio NET has parsed the WSDL, created a proxy object that represents the Web Service (the namespace of the proxy is the name of the server the WSDL was served from, in our case localhost), and cached a local copy of the WSDL This is all visible to us if we expand the Web References section with the Solution Explorer:
Trang 9We can now write code in our Web Application to use the Fibonacci Web Service Double-click on Button1 and write some code for the Button1_Click event handler Once the code view is open, write the following to call the GetSeqNumber
of the Fibonacci Web Service:
Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
Dim fibonacci As New localhost.Fibonacci()
Dim indexIntoSeries As Integer
indexIntoSeries = TextBox1.Text
Label1.Text = fibonacci.GetSeqNumber(indexIntoSeries)
End Sub
We first create an instance of the proxy, fibonacci, by calling New localhost.Fibonacci()
Changing the namespace in this example from localhost to some more meaningful value, such as MathServices, is
as simple as right-clicking on localhost in the Solution Explorer and selecting rename
Next, we declare a local variable, indexIntoSeries This is used as the parameter value for the call to
GetSeqNumber() Next, we extract the value from TextBox1 and assign it to indexIntoSeries - so the user must
Trang 10enter an Integer value We then use our instance, fibonacci, calling the GetSeqNumber() method and passing in the value of indexIntoSeries When the call completes, an Integer is returned, the value of which we assign to Label1.Text
Here's a high-level rundown of what occurs when we run this application and click on Button1:
ASP.NET creates an instance of the proxy, and calls it, passing in the value of TextBox1
The proxy then calls the Fibonacci Web Service via SOAP which, in turn, computes the result, and sends it back
to the proxy via SOAP
The proxy then de-serializes the SOAP message (converts the values within the SOAP message to NET types) and returns an Integer value, which is displayed to the end user
Let's take a look at the sourcecode that Visual Studio NET created
Viewing the Source for the Proxy
Behind the scenes Visual Studio NET has obviously done a lot of work for us - it's created the proxy that can send and receive the SOAP requests and responses
We can access, and modify, the sourcecode that Visual Studio NET creates and compiles for our proxy It's not available
to us by default, but if we right-click on our project in Solution Explorer and select Add Existing Item, a file selection dialog box is opened The location that the file dialog box is currently accessing is the root directory of our project We should see
a folder named localhost (or another name if you renamed the Web Reference) If we open this folder we find the source to our proxy On my server the source file is Fibonacci_cs.vb
Trang 11The proxy is created in whatever language the project is using For this particular example, the proxy source is in VB.NET
as we created a VB.NET ASP.NET Web Application
This file contains the source for our Proxy If we open it, it'll be added to our current project and we can view and/or modify its source
Creating a proxy using Visual Studio NET is simple As long as we have the URL to the WSDL Visual Studio NET takes care
of the rest We can write code, and call methods, just as would expect to with a local class, but in fact the proxy is exchanging SOAP messages with a Web Service
While Visual Studio NET definitely makes using Web Services easy, it isn't required for creating proxy classes If you're using NET, but don't have a copy of Visual Studio NET, you can still automate the process of building proxies to Web Services using the command-line tool wsdl.exe
Creating the Source File
Trang 12Let's start by using wsdl.exe to generate a proxy for a WSDL document available at
http://localhost/wrox/4885/WebServices/Expose/Fibonacci/Fibonacci_cs.asmx?WSDL At the command prompt we can run the following command:
wsdl http://localhost/ /Fibonacci_cs.asmx?WSDL
The result is a source file (by default written in C#) named Fibonacci.cs
By default, if we name an HTTP-based WSDL location, wsdl.exe will use the proxy settings configured for Internet Explorer Alternatively, we can copy the WSDL locally and then run it through wsdl.exe:
Trang 13Use:=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)> _
Public Function GetSeqNumber(ByVal fibIndex As Integer) As Integer
Dim results() As Object = Me.Invoke("GetSeqNumber", New Object() {fibIndex})
Return CType(results(0),Integer)
End Function
Public Function BeginGetSeqNumber(ByVal fibIndex As Integer, ByVal callback As
System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult
Trang 14Return Me.BeginInvoke("GetSeqNumber", New Object() {fibIndex}, callback, asyncState)
End Function
Public Function EndGetSeqNumber(ByVal asyncResult As System.IAsyncResult) As Integer
Dim results() As Object = Me.EndInvoke(asyncResult)
Trang 15public Fibonacci() {
this.Url = "http://localhost/WebServices/Fibonacci_vb.asmx";
}
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/GetSeqNumber", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public int GetSeqNumber(int fibIndex) {
object[] results = this.Invoke("GetSeqNumber", new object[] {
return this.BeginInvoke("GetSeqNumber", new object[] {
fibIndex}, callback, asyncState);
}
public int EndGetSeqNumber(System.IAsyncResult asyncResult) {
Trang 16object[] results = this.EndInvoke(asyncResult);
return ((int)(results[0]));
}
}
Compiling the Source File
Now that we have the proxy source files we need to compile them Included with NET are command-line compilers for C# (csc.exe) and VB NET (vbc.exe) We'll use these to build our proxy classes into assemblies
Compiling the VB.NET Source
To compile the VB NET source file we'll execute the following statement at a command prompt (note that this command
is all one line):
vbc /t:library /out:Fibonacci_vb.dll /reference:System.Web.Services.dll,System.Xml.dll, System.dll Fibonacci.vb
This instructs the VB NET compiler to create a library (.dll), rather than an executable, and to create a file named Fibonacci_vb.dll Finally we instruct the VB NET compiler to use Fibonacci.vb as the input source file The result
is a dll file named Fibonacci_vb.dll
Compiling the C# Source
To compile the C# source file we'll execute the following command (note that this command is all one line):
csc /t:library /out:Fibonacci_cs.dll Fibonacci.cs
The syntax for the VB NET and C# compilers is identical and after executing this statement the result is a dll file named fibonacci_cs.dll
We can copy either of these dll files (we only need one of them) to an ASP.NET application's \bin directory We can then build an ASP.NET application that uses this proxy, just as we did with Visual Studio NET For example:
Trang 17<Script runat="server">
Private Sub Page_Load(sender As Object, e As EventArgs)
Dim fibonacci As New Fibonacci ()
lblResult.Text = fibonacci.GetSeqNumber(6)
End Sub
The value of the 6th element in the Fibonacci series is:
<asp:label id="lblResult" runat="server"/>
In the Visual Studio NET version of this example, we used a Fibonacci proxy that was part of the localhost namespace Our example of the proxy using the command-line tool didn't use a namespace This is a choice we made, we could make the above class part of a namespace with another simple command-line switch: namespace For example:
<url or path> The URL or file path to one of these supported document types that WSDL.exe
recognizes (WSDL Contract, XSD Schema, or DISCO Document)
Trang 18/language:<language>
The language option (short form /l:) allows us to create the proxy in any NET language Three languages are available as part of the SDK that the tool supports: C# (/language:CS), VB NET(language:VB), and
JScript.NET(/language:JS).To use a language other than the these three we must name the class implementing the interface ICodeGenerator For example, if we wish to use Perl we would use a CodeDOM class provided by the NET Perl compiler The default language is C#
/server
By default wsdl.exe will create client proxies for a given WSDL document However, if we use the /server option wsdl.exe will generate a source file with abstract members that represents the server implementation of the Web Service This option is useful if several organizations agree upon the structure of the Web Service (as defined by the WSDL), but would like to provide their own implementations
/namespace:<namespace>
The /namespace (short form /n:) option allows us to set the namespace that the proxy class is generated within By default no namespace is used For example, we can generate a proxy class within a namespace of MathSamples by simply setting /n:MathSamples
/username:<username> The /username parameter (short form /u:) is set when we use a URL to access
the WSDL, DISCO, or XSD Schema and the server requires authentication
/password:<password> The /password parameter (short form /p:) is set when we use a URL to access
the WSDL, DISCO, or XSD Schema and the server requires authentication
/domain:<domain> The /domain parameter (short form /d:) is set when we use a URL to access the
WSDL, DISCO, or XSD Schema and the server requires authentication
/proxy:<url> The proxy server used for HTTP requests By default the proxy settings defined
for Internet Explorer will be used
/proxyusername:<username> The name of the user to authenticate to the proxy server with
/proxypassword:<password> The value of the proxy user's password to authenticate to the proxy server with /proxydomain:<domain> The name of the proxy user's domain to authenticate to the proxy server with
/appsettingsurlkey:<key>
Rather than hard-coding the URL specified in the WSDL document, a URL can be stored in ASP.NET configuration system's <appSettings> section We can use the appsettingsurlkey parameter with wsdl.exe to name the key that corresponds to the value stored in the configuration file
Trang 19/appsettingsbaseurl:<baseurl> When used in conjunction with the appsettingsurlkey this parameter allows
us to name the base URL for the Web Service
Now that we know how to use both Visual Studio NET and wsdl.exe to create a proxy class, we can discuss the proxy that's generated It inherits some properties and methods from a base class, and as we'll see, these properties and methods give us even more control over how we interact with the Web Service that the proxy represents
Using the Proxy Class
If we build and use the proxy class in Visual Studio NET we can see (through statement completion) that the class contains additional methods and properties beyond the methods used in our Web Service For example, the Fibonacci class supported a GetSeqNumber() method, however, if we examine the proxy for Fibonacci in Visual Studio NET we'll see several other methods and properties that Fibonacci supports This is because the Fibonacci proxy class inherits these methods and properties from a base class
A proxy inherits from SoapHttpClientProtocol, which inherits from HttpWebClientProtocol, which in turn inherits from WebClientProtocol
Let's examine some of the common methods and properties we might use
Controlling Timeout
We still need to write our applications so that they behave correctly when the Web Service is not performing correctly For example, the network connection between the provider and the consumer of the service could become saturated so that responses start to take too long Requests are issued, and the consumer of the service simply waits until the request times out The default timeout for a request from our proxy is ninety seconds
The following VB NET code illustrates a simple Add Web Service that performs slowly due to a call to
Thread.Sleep(20000) that forces the thread to wait 20 seconds before continuing:
Trang 20<WebMethod()> Public Function Add(a As Integer, b As Integer) As Integer
<Script runat="server">
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim example As New Timeout()