Returning Complex Data from a Web Service

Simple data can be returned by using the HTTP protocol. Complex data (instances of structures or classes) uses the SOAP protocol. It is worth knowing when various protocols come into play. SOAP used to mean Simple Object Access Protocol; but now SOAP is just SOAP. However, the old expansion of the acronym describes nicely what SOAP does for us. SOAP makes it possible to transport an object across a network by using the self-describing nature of XML to include the description of the data along with the data.

Writing Web Services that return complex data types requires no special effort; however, you need to be aware of some additional things that happen with the related technologies. Thus I will show you a class and a Web Service that returns data representative of data that might be returned from a clearing corporation like the National Securities Clearing Corporation (if it were using Web Services) and the resulting impacts and opportunities for the Web Service consumers.

Implementing a Complex Type

Complex data in this context refers to structures or classes. You can define a class or structure and return it from a Web Service in much the same manner as you would return a class or structure from any DLL. The class I defined for this example (Listing 14.3) represents information that might be returned by a commissions clearing Web Service.

Listing 14.3. The CommissionsData Class
Public Class CommissionsData
  Private FSystemCode As String
  Private FRecordType As String
  Private FClearingSettlingFirmNumber As String
  Private FFundProcessingDate As DateTime
  Private FCommissionType As String
  Private FDebitCreditIndicator As String
  Private FDebitReasonCode As String
  Private FSettlementIndicator As String
  Private FRecordDate As DateTime

  Public Property SystemCode() As String
  Get
    Return FSystemCode
  End Get
  Set(ByVal Value As String)
    FSystemCode = Value
  End Set
  End Property

  Public Property RecordType() As String
  Get
    Return FRecordType
  End Get
  Set(ByVal Value As String)
    FRecordType = Value
  End Set
  End Property

  Public Property ClearingSettlingFirmNumber() As String
  Get
    Return FClearingSettlingFirmNumber
  End Get
  Set(ByVal Value As String)
    FClearingSettlingFirmNumber = Value
  End Set
  End Property

  Public Property FundProcessingDate() As DateTime
  Get
    Return FFundProcessingDate
  End Get
  Set(ByVal Value As DateTime)
    FFundProcessingDate = Value
  End Set
  End Property

  Public Property CommissionType() As String
  Get
    Return FCommissionType
  End Get
  Set(ByVal Value As String)
    FCommissionType = Value
  End Set
  End Property

  Public Property DebitCreditIndicator() As String
  Get
    Return FDebitCreditIndicator
  End Get
  Set(ByVal Value As String)
    FDebitCreditIndicator = Value
  End Set
  End Property

  Public Property DebitReasonCode() As String
  Get
    Return FDebitReasonCode
  End Get
  Set(ByVal Value As String)
    FDebitReasonCode = Value
  End Set
  End Property

  Public Property SettlementIndicator() As String
  Get
    Return FSettlementIndicator
  End Get
  Set(ByVal Value As String)
    FSettlementIndicator = Value
  End Set
  End Property

  Public Property RecordDate() As DateTime
  Get
    Return FRecordDate
  End Get
  Set(ByVal Value As DateTime)
    FRecordDate = Value
  End Set
  End Property

End Class

There isn't anything especially noteworthy about the CommissionsData class; it is comprised of fields and properties. I used the F prefix convention for fields and dropped the F prefix for properties. (Not even Microsoft is promoting the Hungarian notation anymore.)

Note that the class contains only fields and properties. We could implement methods and events for this class. However, there would be no impact on how we would implement the Web Service.

Implementing a Web Service

The CommissionsData class represents a complex type that we want to return from a Web Service. For our illustration it doesn't matter whether or not we have any data assigned to the members of CommissionsData. If we returned an instance of CommissionsData, that data would be returned along with the definition of the type when we invoked the Web method. Listing 14.4 demonstrates a simple Web method that returns a CommissionsData object.

Listing 14.4. A Web Method That Returns a CommissionsData Object
Imports System.Web.Services

<WebService(Namespace:="http://tempuri.org/")> _
Public Class Service1
  Inherits System.Web.Services.WebService

  [ Web Services Designer generated code ]
  <WebMethod()> _
  Public Function GetData() As CommissionsData.CommissionsData
    Return New CommissionsData.CommissionsData()
  End Function

End Class

If you compare the Web Services in Listings 14.2 and 14.4, you will note that there are fundamentally no differences in the mechanics of implementing the Web Services. All the differences occur when the WSDL utility generates the proxy class and when we use the Web Service that returns a complex type.

Referencing a Web Service

When you add a Web reference to a project consuming a Web Service (see Chapter 13), WSDL generates several files. These files help bridge the gap between your Web Service and the client that consumes the Web Service. If you click on the namespace created by WSDL and then click the Show All Files toolbar button, the Reference.vb proxy file will be displayed in the Solution Explorer (Figure 14.2). You can also select the Reference.vb file from Windows Explorer by navigating to it and opening that file.

Figure 14.2. Click the Show All Files button to show the Reference.vb proxy file generated by the WSDL utility.


Exploring the Proxy Class

When you have added a Web reference to the Commissions Web Service, a proxy class is added to your project. (You can open the proxy class for the Commissions Web Service and follow along as we explore.) Listing 13.3 in the previous chapter shows an entire proxy file, and of course you can create a Web Service, reference it, and examine that proxy file too. For now we are interested only in the treatment of our CommissionsData class by the WSDL utility. Listing 14.5 shows just the generated CommissionsData proxy file.

Listing 14.5. The CommissionsData Proxy File Generated by WSDL
<System.Xml.Serialization.XmlTypeAttribute( _
[Namespace]:="http://tempuri.org/")> _
  Public Class CommissionsData

    '<remarks/>
    Public RecordDate As Date

    '<remarks/>
    Public SystemCode As String

    '<remarks/>
    Public SettlementIndicator As String

    '<remarks/>
    Public RecordType As String

    '<remarks/>
    Public ClearingSettlingFirmNumber As String

    '<remarks/>
    Public FundProcessingDate As Date

    '<remarks/>
    Public CommissionType As String

    '<remarks/>
    Public DebitCreditIndicator As String

    '<remarks/>
    Public DebitReasonCode As String
  End Class
End Namespace

Note that the generated proxy class contains only fields—no properties, methods, or events (or anything else, for that matter). I refer to this as flattening the complex type. All our properties become public fields in the proxy class. If you think about this for a minute, it makes sense.

If Web Services returned fat objects—with methods, events, properties, and other code—Web Services would have to return all the assemblies and related assemblies across the wire. This means that Web Services would have to download and install binary files. For complex Web Services you might be referring to half of the CLR. Clearly, sending the CLR across the Web for each Web method invocation would not be a good thing. Even worse is that you might be dragging third-party code onto your workstation or server. (You don't know where that code has been.) Instead Web Services return a sanitary proxy class capable of containing data. So, in a way we are back to data-only data types, but just for Web Services. (Later in this chapter I will show you how to return fat objects from Web Services.)

Implementing the Web Service Consumer

The mechanism behind the WSDL tool is (probably) the CodeDOM. The CodeDOM contains classes that can generate very complex code. Thus far we know that almost everything about returning complex types in a Web Service is no more challenging than returning a simple type. The big difference is that the Web Service has the real class and the consumer gets a fields-only replica.

Clearly, you will not be able to invoke operations on the proxy class returned by the Web Service, but you can use the data. Listing 14.6 demonstrates a simple use of the proxy CommissionsData class: I use the fields information to generate a simple user input form. (This is for fun as much as for the hope that you'll find it a useful application for Reflection.)

Listing 14.6. Using Reflection to Generate a Simple User Interface
1:  Imports Service = CommissionsDataApp.localhost.Service1
2:  Imports System.Reflection
3:
4:  Public Class Form1
5:    Inherits System.Windows.Forms.Form
6:
7:  [ Windows Form Designer generated code ]
8:
9:    Private Sub Form1_Load(ByVal sender As System.Object, _
10:     ByVal e As System.EventArgs) Handles MyBase.Load
11:
12:     Dim Service As Service = New Service()
13:
14:     GenerateForm(Service.GetData().GetType())
15:
16:   End Sub
17:
18:   Private Sub GenerateForm(ByVal Type As Type)
19:
20:     Dim Info As FieldInfo
21:     Dim Y As Integer = 0
22:     Dim Label As Label
23:     Dim TextBox As TextBox
24:
25:     For Each Info In Type.GetFields()
26:
27:       Label = New Label()
28:       Label.Text = Info.Name
29:       Label.Location = New Point(10, Y)
30:       Label.AutoSize = True
31:       Controls.Add(Label)
32:
33:       TextBox = New TextBox()
34:       TextBox.Location = New Point(20 + Label.Width, Y)
35:       Controls.Add(TextBox)
36:       Y += 25
37:
38:     Next
39:
40:   End Sub
41: End Class

The code in Listing 14.6 is direct. I used the aliasing trick to shorten the namespace reference in line 1. I imported the System.Reflection namespace, which contains the FieldInfo class used to reflect the CommissionsData proxy class in lines 20 and 25. When the form loads (lines 12 and 14), I create an instance of the service and a simple user interface (Figure 14.3).

Figure 14.3. A user interface dynamically generated by using Reflection.


A practical application might be a form generator. For a commercial application we might employ the CodeDOM and generate actual code, supporting programmer customization. More likely, though, you will be using the data returned by the Web Service.

Downloading binary assemblies with executable code would not be secure. However, what if you download code that you know is reliable? For example, Microsoft supports returning DataSet objects from a Web Service, and these include methods too. Because the DataSet class contains known code from Microsoft and it is assumed that you have the CLR on the machine using the DataSet Web Service, it seems reasonable to support fat DataSet objects from Web Services. Let's take a look at how that works.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.121.8