Upgrade Legacy Apps to Web Services
Here are some tips to improve your security and performance when you upgrade.
by Federico Zoufaly
VSLive! Orlando, September 19, 2002
Note: Federico Zoufaly presented "Converting Your Source Code for Web Services" at VBITS Orlando, Wednesday, September 18. This tip is from that session.
When upgrading Visual Basic applications to .NET and Web services, you must address some implementation issues. I'll provide some tips to deal with unsolved references in Web services, provide security, and improve performance.
The approach I suggest has two main steps. The first step is to take your Visual Basic 6 application, upgrade it to Visual Basic .NET, and achieve a state of functional equivalence. That is, the first step is to assure that your application behaves the same in .NET. Once you have reached functional equivalence, you can start to work on rearchitecting your application and expose some Web services.
To generate a Web service with Visual Studio .NET, you have to locate the functionality (method) you want to expose and then copy it and all its dependencies to a new Web service project. Although this can sound simple, you must take many technical aspects into account.
Dependencies Resolution
Once you have located and isolated the method you want to expose as a Web service and created the Web service project, you need to move your code to the new project. When you move code, some references to necessary items that were left in the original application appear unbound. There are several ways to deal with this problem.
Reference: In some cases, you can fix the problem simply by adding a reference to a library. In this example, the code needs an additional reference to the ADODB library:
<WebMethod()> _
Function GetOrders(ByRef CustomerID _
As String) As String
Dim cn As Object
Dim rs As New ADODB.Recordset
Copy: When the code references a module or class in the original application, that component can be directly copied to the new project. You might need to perform this step recursively until you have removed all unbound references.
Wrapper: When you are upgrading a code component that is being accessed from multiple applications, it is preferable to wrap the Web service inside the original component. This way, it is not necessary to modify every application that accesses a function, thus reducing redundancies and simplifying maintenance. In this approach, code of methods that were moved to WebMethods is substituted with calls to the Web services method:
'Non-modified interface procedure on
'the client
Private Sub frmOrder_Load(ByVal _
eventSender As System.Object, ByVal _
eventArgs As System.EventArgs) Handles _
MyBase.Load
Dim c As New clsCustomer
Me.grd.Recordset = StringToRs( _
c.GetOrders(Customer_ID))
End Sub
'Modified DLL function on the server
'(wrapper)
Function GetOrders(ByRef CustomerID _
As String) As String
Dim ws As New localhost.Service1()
Return ws.GetOrders(CustomerID)
End Function
'Upgraded WebMethod on the server
<WebMethod()> _
Function GetOrders(ByRef CustomerID _
As String) As String
Dim rs As New ADODB.Recordset
Dim rsReturn As New ADODB.Recordset
'WebMethod code
GetOrders = RsToString(rsReturn)
End Function
Security
When you expose a Web service, understand that the location and execution mechanism of your code changes, and this change requires you to revise your security policies mechanism. All data sent and received by a Web service is formatted using SOAP on top of an XML specification. SOAP messages are easily readable, so it is necessary to encrypt certain data such as passwords. You can do this with the System.Security.Encryption namespace, which provides several cryptographic algorithms. In this example, you encrypt a password sent as a parameter to the WebMethod ValidatePassword, using the RSA algorithm. The private key (used to decrypt data) is kept inside the RSAParam structure on the server, which can be obtained through the ExportProperties method of the RSACryptoServiceProvider:
'Client side function
Function Login(ByVal UserName As String,_
ByVal Password As String) As Boolean
Dim cs As New CspParameters()
cs.Flags = _
CspProviderFlags.UseMachineKeyStore
Dim rsa As New _
RSACryptoServiceProvider(cs)
Dim Pwd As Byte() = _
System.Text.Encoding. _
Unicode.GetBytes(Password)
Return ValidatePassword(UserName, _
rsa.Encrypt(Pwd, False))
End Function
<WebMethod()> _
Function ValidatePassword(ByVal UserName _
As String, ByVal Password() As Byte) _
As Boolean
Dim cs As New CspParameters()
cs.Flags = CspProviderFlags. _
UseMachineKeyStore
Dim rsa As New _
RSACryptoServiceProvider(cs)
rsa.ImportParameters(RSAParam)
Dim BytesDecPwd As Byte() = _
rsa.Decrypt(Password, False)
Dim StrDecPwd As String = _
System.Text.Encoding. _
Unicode.GetString(BytesDecPwd)
Return ValidPassword(UserName, _
StrDecPwd)
End Function
Performance
Web services communicate with the external world by sending XML messages. XML messages are a platform-independent textual representation of information. If performance is an issue, Web services might not be the right implementation.
Some architectural characteristics of the original application can affect performance in the upgraded Web service.
"Chatty" interfaces: Multiple sequential calls between an interface and a business logic layer are acceptable in an application server environment, but they cause a big performance loss when it comes to Web services. The solution to this problem is to group related calls into single, heavier calls, avoiding repetitive data transmissions.
Serialization: Complex objects and data structures must be serialized to be transmitted, causing an overhead due to serialization, deserialization, and the volume of serialized data. There are two kinds of serialization.
- XML Serialization: This is the default serialization model. When your WebMethod returns a complex data structure, it is serialized to XML, producing a significant overhead in the size of the data being transmitted. XML, or SOAP serialization, is platform-independent.
- Binary serialization: Objects are serialized into a sequence of bytes, and transmitted inside a SOAP envelope. This reduces the overhead introduced by XML serialization, but platform independence is lost. Also, it is necessary to introduce some code to manage the serialization and deserialization processes:
<WebMethod()> _
Function test() As Byte()
Dim BinFormatter As New
System.Runtime.Serialization. _
Formatters.Binary.BinaryFormatter()
Dim s As New System.IO.MemoryStream()
BinFormatter.Serialize(s, New clsUtils())
'This converts the memory stream into an
'array of bytes
Return s.ToArray
End Function
I've covered some technical issues involved in upgrading to Web services. As you've seen, the upgrade process requires a deep analysis of the code dependencies and the functionality to be exposed to ensure you understand the differences between a normal method call and a call to a Web service.
About the Author
Federico Zoufaly, cofounder and CTO at ArtinSoft, is responsible for managing the company's Microsoft Technologies division. Zoufaly received a bachelor's degree in electronic engineering and a master's degree in computer science from the Instituto Tecnologico de Costa Rica (ITCR). He is currently pursuing a Ph.D. from The University of Florida at Gainesville, working toward a dissertation on Active Databases and Workflows. Reach ArtinSoft by e-mail at info@artinsoft.com.
|