Beruflich Dokumente
Kultur Dokumente
Upgrading Distributed
Applications
Until now we haven’t really talked about upgrading large-scale distributed
applications. But building these types of applications is, after all, the corner-
stone of the entire Microsoft .NET initiative. The .NET Framework is designed
from the ground up to support new first-class distributed technologies. Know-
ing how these technologies are implemented is critical in assessing how to
upgrade a given application. Unfortunately, so many possibilities and variations
exist that it is impossible to address all or even a significant portion of them in
a meaningful way.
This chapter gives an overview of the core concepts behind large-scale
distributed applications. It then discusses how these concepts are implemented
in Visual Basic .NET. We highlight the use of these technologies and describe
how to implement them in your applications. Although this chapter covers
some interoperability issues (such as how to build wrappers and marshal
objects such as ADO Recordsets from the server to the client), there are others
you may face if you get creative with your application. Consult Chapter 13 for
more information regarding COM interoperability.
Note Some of the examples in this chapter use the Northwind data-
base Northwind.mdb (included on the companion CD) as a basis for
demonstrating various forms of data access.
435
C2161587x.fm Page 436 Friday, November 16, 2001 9:08 AM
In-process
Out-of-process
Remote process
Time
F21km01
So while we can call into local methods without any concern for over-
head, and even out-of-process overhead isn’t too bad, we need to be extra care-
ful of not only how often we call remote methods but also how much work
these methods do. Think of it this way: since the overhead is greater, we need
to make the method calls worthwhile. Consider the following example to help
demonstrate what we mean. It shows the difference between setting properties
on an object—a typically simple operation with low overhead—and using a sin-
gle method to set all the properties at once.
This example uses two different approaches, but it does not really clarify
why one is better than the other. For this, look to Figure 21-2. It should help
you visualize the differences between the approaches and understand how they
affect an application’s performance. Approach 1 is “chatty” in that each prop-
erty access involves a separate network operation, whereas approach 2 is
“chunky” because it accomplishes its task with a single network operation.
At this point, it should be clear that the design of your remote objects and
interface is vitally important to your application’s scalability and performance.
When you look at the performance of approach 1, you should also understand
that when you access any remote object you are consuming resources on the
remote server, which means that fewer connections are available to other appli-
cations. The more efficient your design, the better your application will perform
and the better it will scale up in an enterprise environment.
C2161587x.fm Page 439 Friday, November 16, 2001 9:08 AM
Controls
Utility classes
Business logic
Utility classes
SQL
F21km03
The most important part here is the use of the WebMethod attribute. This
attribute tells the compiler to generate the XML contract for the Web service,
register it for discovery, and produce the implementation code necessary for
marshaling parameters and return objects. It also enables you to filter the meth-
ods of your XML Web service class and publish only the methods you want to
make publicly available over the Internet. Think of this filtering as taking access
protection a step further. You’re already familiar with creating public, private,
and friend methods. But there will probably be situations in which your appli-
cation architecture requires a public method on your XML Web service class
that you do not want to make available through the XML Web service itself. In
such cases, the power of the WebMethod attribute really shines. It gives you
absolute control over what you publish over the Internet without requiring you
to sacrifice good component design in your XML Web service classes. The fol-
lowing excerpt from the SimpleService.asmx.vb file (part of the SimpleWebSer-
vice sample project) demonstrates the WebMethod attribute in action:
You can do much more with the WebMethod attribute, such as manipulate
additional settings, but we will use it in its simplest, most basic form, as dem-
onstrated here. The MSDN documentation gives a more thorough treatment of
the use of this attribute, above and beyond its default behavior.
Now is a good time to talk about restrictions on parameters and return val-
ues for XML Web services. An XML Web service is not a bidirectional object.
This means that you cannot pass objects by reference; they must always be
passed by value. In other words, your parameters and return values must be
serializable. Most, if not all, of the intrinsic data types in Visual Basic .NET and
the .NET Framework support serialization as long as the objects themselves are
self-contained—that is, as long as they don’t represent or contain any physical
system resources, such as database connections or file handles. For your cus-
tom classes you have two options. You can implement the ISerializable inter-
face for your class, but this is the more manual process. Alternatively, you can
use the Serialize class attribute. This option enables your class to serialize itself.
No work is necessary on your part unless one or more of the types contained
in your class do not support serialization. In such cases, you have the choice of
adding the Serializable attribute to those classes (if they are under your control)
or implementing the serialization yourself with the ISerializable interface.
C2161587x.fm Page 443 Friday, November 16, 2001 9:08 AM
F21km04
F21km05
As you can see, a great deal of information is available through this page.
You can also invoke the method (using the Invoke button) and view the SOAP
result message. Additionally, if the service accepts parameters, this page will
have input boxes for each of the parameters. There are some limitations to this,
however. If your methods require parameters in a binary format (a Byte array,
for example), you will need to invoke the method programmatically.
The result of invoking the HelloWorld method is displayed in a separate
window and looks like this:
Pretty neat, huh? Now we need to look at how you can use this method in an
application.
You can see the results in Figure 21-6. This sample project helps demon-
strate how XML Web services simplify the development of distributed applica-
tions. XML Web Services are a powerful tool that enable the development of
fundamentally different kinds of applications, due to its platform- and lan-
guage-independent nature.
C2161587x.fm Page 446 Friday, November 16, 2001 9:08 AM
F21km06
Moving On
This is all well and good, you may be thinking, but what about my existing
applications? How should I implement XML Web services in an existing COM
or managed application? Does it require redesign, or are there alternatives?
Read on….
COM
object ADO Recordset
Recordset
in XML
WebMethod WebMethod
call return
Recordset
Button Click
in XML
ADO Recordset
F21km07
To give you a better feel for how this process works, we’ve provided a
sample on the companion CD called Web Services and ADODB. The sample
consists of two projects: an XML Web service (NorthwindDatabase) and a Win-
dows Forms client application (Northwind Viewer). The design of the sample is
simple. One method is available through the XML Web service that allows the
client to specify a SQL query string and returns the result as an XML represen-
tation of the resulting Recordset.
The following is the implementation code for the XML Web service. The
Query method does all the work. You can see that this method takes a query
string as a parameter and returns a string. As we have discussed previously, this
return string contains the XML representation of the Recordset returned by the
specified query. This project references ADODB and uses the ADO Connection
object directly to execute the query. It would also work just fine with a regular
COM object that returns a Recordset; we are just trying to make the sample as
clear and concise as possible.
C2161587x.fm Page 449 Friday, November 16, 2001 9:08 AM
Imports ADODB
Imports System.Web.Services
<WebService(Namespace:="http://tempuri.org/”)> _
Public Class NorthwindDatabase
Inherits System.Web.Services.WebService
Try
‘ You will need to specify the local path to your copy
‘ of the Northwind.mdb file. This is just an example.
conn.Open( “Provider=Microsoft.Jet.OLEDB.4.0;” & _
“Data Source=c:\Northwind.mdb”)
Catch e As Exception
Return Nothing
End Try
Dim rs As Recordset
Try
rs = conn.Execute(queryString)
Catch e As Exception
conn.Close()
Return Nothing
End Try
str.Close()
rs.Close()
conn.Close()
End Function
End Class
After the query has been executed, we use the ADODB Stream class to
serialize the contents of the Recordset. (In Chapter 20, we touched on XML seri-
alization for Recordsets and introduced the concept with the RsToString and
StringToRS methods.) Notice that there are no particular requirements as to the
type of Recordset used. This example uses a forward-only Recordset (which is
more than sufficient), but it would work equally well with any kind of client or
server-side cursor. Also notice that we close out all the ADO classes (Stream,
Recordset, and Connection). Chapter 10 discusses why this step is crucial.
C2161587x.fm Page 450 Friday, November 16, 2001 9:08 AM
Now that we have the XML Web service, we need something to test it. The
test sample, Northwind Viewer, has a couple of interesting features. Not only
does it deserialize a Recordset from XML, but it also uses the OleDbDataAdapter
to convert the Recordset to an ADO.NET DataTable. It then sets the DataSource
property of the QueryDataGrid using the newly created table. That’s it, aside
from additional initialization code in the form’s Load event. We should point
out one thing here. We instantiate the XML Web service proxy only once in the
Load event, rather than on every button click. This practice is perfectly accept-
able because the proxy class does not represent an active network connection.
Connections are made only when a method on the class is invoked, so we don’t
bother creating the same proxy over and over. Creating it once is sufficient.
Again, notice that we clean up the ADO objects by calling Close. Always play
nice with your COM objects and clean up afterward.
Imports ADODB
Imports System.Data
Imports System.Data.OleDb
xml = nwdb.Query(QueryComboBox.Text)
If xml Is Nothing Then
QueryDataGrid.DataSource = Nothing
MsgBox(“The query failed!”)
Exit Sub
End If
C2161587x.fm Page 451 Friday, November 16, 2001 9:08 AM
da.Fill(table, rs)
QueryDataGrid.DataSource = table
rs.Close()
str.Close()
End Sub
End Class
Figure 21-8 demonstrates the test application in action. You can see that
the user selects a query from the ComboBox and then clicks the Execute but-
ton. Another neat feature of this application is that the ComboBox is editable at
run time, so you can further customize the query.
F21km08
You should now be able to see how you might get started wrapping your
application with XML Web services. Depending on how your application is
implemented, it is quite possible to handle the serialization issues without a
great deal of disruption. An advantage is that it is extremely easy to create a
test XML Web service to discover how your application will behave and what
is feasible.
C2161587x.fm Page 452 Friday, November 16, 2001 9:08 AM
Remoting
As we mentioned earlier, remoting is the process of communication between
different operating system processes, regardless of whether they are on the
same computer. It simplifies communication between objects living in different
application domains, possibly on different computers, and between different
contexts, possibly in different application domains. The remoting framework is
built into the common language runtime and can be used to build sophisticated
distributed applications. Some of the features provided by .NET remoting are as
follows:
■ Proxy objects
■ Object passing
■ Activation models
■ Stateless and stateful objects
■ Channels and serialization
■ Lease-based lifetime
■ Hosting objects in IIS
The most basic remoting scenario requires a client application and a min-
imal host process. The host process must register specific object types with the
runtime and specify the desired configuration details. Remoting itself can be
thought of as an abstraction layer over a transport protocol that enables appli-
cations to instantiate objects that may reside on remote machines and work
with them as if they were local. It is an interesting technology because it is
removed from the underlying transport protocol. What this means is that, unlike
DCOM, you have choices as to how your client and server processes talk to
each other.
Currently, remoting supports two transport protocols: TCP/IP and HTTP.
Each has its advantages, depending on your requirements. TCP/IP offers the
better performance by far. It is basically a low-level binary protocol that enables
virtually direct communication with the remote objects. This protocol tends to
work well in an intranet environment in which you have unrestricted TCP port
usage. Using TCP/IP becomes problematic when you need to support clients
across multiple sites or over the Internet. Most corporations have firewalls that
block anything but the standard TCP/IP ports, which would render a remoting
application using a custom TCP/IP port unusable.
The solution is the HTTP protocol. Firewalls are almost always configured
to allow traffic over TCP/IP port 80 (the port used by the World Wide Web).
Using HTTP, your remoting applications can communicate freely over the span
of the Internet. The downside is that HTTP is nowhere near as efficient as
TCP/IP. When you specify HTTP as your remoting transport protocol, you
C2161587x.fm Page 453 Friday, November 16, 2001 9:08 AM
basically end up with XML over HTTP. Serializing your objects into XML is not
as compact as using a binary format. It increases the size of the payload,
increases processing resources on both the client and server, and takes longer
to transmit. This extra overhead means that a method call over HTTP costs
more than one over TCP/IP. Will you notice the difference in casual use? Not
really. But it does have implications for larger-scale applications. It’s nothing to
worry about, just something to keep in mind.
As far as requirements for objects capable of remoting go, there is only
one that is significant: they must derive the MarshalByRefObject class. Notice
that this is a built-in feature of COM+ classes because the ServicedComponent class
has MarshalByRefObject as a base class. Now is a good time to look at an example.
From the application’s perspective, the critical part is the server project,
which is responsible for registering the remoting object with the host runtime.
The code for doing this is fairly simple and looks like the following:
Process Process
starts starts
Create channel
and register
SimpleClass type
Channel opened
SimpleClass
registered
SimpleClass Request
instantiated SimpleClass proxy
Loop
Call GetDateTime
SimpleClass
method
proxy
Terminate proxy
Process
ends Channel closed
SimpleClass
unregistered
Process
ends
F21km09
As you can see, we need to keep this process running in some form or
another; otherwise, our client is out of luck. Speaking of the client, here is what
it looks like.
C2161587x.fm Page 455 Friday, November 16, 2001 9:08 AM
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Dim sc As SimpleClass
Private Sub DateTimeButton_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles DateTimeButton.Click
If Not Initialize() Then Return
MsgBox(sc.GetDateTime(), MsgBoxStyle.DefaultButton1, _
“GetDateTime()”)
End Sub
If sc Is Nothing Then
MsgBox(“Could not initialize the remoting client. “ & _
“Check your configuration.”)
Return False
End If
End If
Return True
End Function
End Class
From this example, you can see how the client initializes the SimpleClass
proxy by making the request of the Activator class. An important configuration
requirement that is not obvious here is that both the client class and the server
class must reside in the same namespace. That is why both the server code and
C2161587x.fm Page 456 Friday, November 16, 2001 9:08 AM
the client code refer to Server.SimpleClass. Both projects have a copy of the
class, and their namespaces match. This allows the client to know the fully
qualified type of the SimpleClass that is also known to the server process. The
application itself should look like Figure 21-10.
F21km10
While this example will work, it is not the most desirable way to go about
implementing remoting in an application—especially in a larger-scale applica-
tion. This observation leads us to a discussion of the best architecture for an
application that uses remoting.
Interfaces assembly
INorthwind
Project reference
INorthwind INorthwind
Database Proxy
F21km11
The next code example is the actual database class that was created to
implement the INorthwindDatabase interface. Notice that the class contains
other public methods that do not exist in the interface. As far as the class is
C2161587x.fm Page 458 Friday, November 16, 2001 9:08 AM
concerned, these are utility methods that the client should not be able to call
(the ExecuteQuery method, for example).
Requiring the client to use the interface, instead of the actual class defini-
tion, has two effects. First, it prevents the client from using methods it should
not have access to. Second, it allows you to create other database classes based
on the same interface and use them all interchangeably without having to make
any modifications to the client application. The implementation class, in this
example database, is derived from ServicedComponent instead of directly from
MarshalByRefObject, for the sake of demonstrating how easy it is to support
COM+ and remoting simultaneously.
Imports MyInterfaces
Imports System.Data
Imports System.Data.OleDb
Imports System.EnterpriseServices
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Return True
End Function
End Class
Imports System.EnterpriseServices
Imports System.Reflection
<Assembly: AssemblyKeyFile(“SoapServicesTest.snk”)>
<Assembly: ApplicationName(“COM+ SOAP Services Test”)>
<Assembly: ApplicationActivation(ActivationOption.Server,
SoapVRoot:="SOAPServicesTest”)>
Note There is a caveat to the “just works” mantra for COM+ proxy
applications. It turns out that there are some platform requirements for
this to work correctly. Because of problems in Windows 2000, support
for .NET-based application proxies will not be available until Service
Pack 3 has been released. At the time of this writing, Service Pack 2 is
the most recent available. Application proxies will work just fine on Win-
dows XP and the Windows .NET server product family.
Conclusion
At this point you should have at least a basic understanding of how to imple-
ment the core distributed technologies and where the relative strengths of
remoting and XML Web services lie. Traditionally, developing distributed appli-
cations has required a lot of work on the part of the developer. Microsoft started
to make things a great deal easier with the introduction of Microsoft Transaction
Services (MTS) and RDS. The .NET platform takes the process to a whole new
level. With objects that support the innate capability of serialization and proto-
col abstraction, you are free to concentrate more on the architecture and design
of your applications rather than spend time on network and marshaling issues.
Moving forward, you need to think carefully about what type of solution
will fit well with your application. It is possible, and sometimes desirable, to
maintain some components in Visual Basic 6 rather than moving the entire
application to Visual Basic .NET. Don’t feel pressured to make unnecessary
changes just to be “pure” .NET. Visual Basic .NET provides the groundwork for
developing whole new classes of distributed applications, but this need not be
at the expense of your existing applications.