Click to Rate and Give Feedback
Related Articles

Udi Dahan explains how his team identified and overcame unforeseen problems while developing a large-scale software + services trading application.

Udi Dahan

MSDN Magazine April 2009

...

Read more!

Microsoft Velocity exposes a unified, distributed memory cache for client application consumption. We show you how to add Velocity to your data-driven apps.

Aaron Dunnington

MSDN Magazine June 2009

...

Read more!

Cobra, a descendant of Python, offers a combined dynamic and statically-typed programming model, built-in unit test facilities, scripting capabilities, and much more. Feel the power here.

Ted Neward

MSDN Magazine June 2009

...

Read more!

This column shows you how to secure the .NET Services Bus and also provides some helper classes and utilities to automate many of the details.

Juval Lowy

MSDN Magazine July 2009

...

Read more!

In this article, we show you how to integrate a Windows Services-based solution with SharePoint. The results enable you to provision, start, stop, and remove service instances through SharePoint 3.0 Central Administration.

Pav Cherny

MSDN Magazine April 2009

...

Read more!

Also by this Author

Build a control that allows the user to drag and drop other controls onto the new control at run time, and allow the user to move the control around on a form, all in Visual Basic.

Ken Spencer

MSDN Magazine May 2003

...

Read more!

Ken Spencer

MSDN Magazine April 2003

...

Read more!

Ken Spencer

MSDN Magazine December 2002

...

Read more!

Ken Spencer

MSDN Magazine October 2002

...

Read more!

Ken Spencer

MSDN Magazine December 2003

...

Read more!

Popular Articles

The MVP pattern helps you separate your logic and keep your UI layer free of clutter. This month learn how.

Jean-Paul Boodhoo

MSDN Magazine August 2006

...

Read more!

James Avery does it again with his popular list of developer tools. This time he covers the best Visual Studio add-ins available today that you can download for free.

James Avery

MSDN Magazine December 2005

...

Read more!

Here we introduce you to some of the concepts behind the new F# language, which combines elements of functional and object-oriented .NET languages. We then help you get started writing some simple programs.

Ted Neward

MSDN Magazine Launch 2008

...

Read more!

We introduce you to the benefits of building composite applications with the Composite Application Guidance for WPF from Microsoft patterns & practices.

Glenn Block

MSDN Magazine September 2008

...

Read more!

Ray Djajadinata

MSDN Magazine May 2007

...

Read more!

Advanced Basics
Passing Data Between Objects in an Application
Ken Spencer

Code download available at: AdvancedBasics0307.exe (178 KB)
Browse the Code Online

Q What is the best way to pass data between layers in an application? There seems to be a myriad of choices.
Q What is the best way to pass data between layers in an application? There seems to be a myriad of choices.

A Passing data between forms, classes, Web pages, and Web Services is always a challenge. While it may seem quite simple at first, application demands may place different requirements on data at the endpoints and require certain changes to its format.
A Passing data between forms, classes, Web pages, and Web Services is always a challenge. While it may seem quite simple at first, application demands may place different requirements on data at the endpoints and require certain changes to its format.
How many ways can you move data between parts of an operation? Let me take a stab at a short listing:
  • Structures
  • Classes (with serialization and without)
  • Arrays, collections
  • DataSets, DataTables, DataRows
  • XML
  • Shared variables
  • Public properties exposed from classes
There are other methods, but these are some of the common ones. Let's take a couple of these approaches and look at the pros and cons of each. Before you begin, you should think about what you are going to do with the data when it arrives at its destination. If you are going to use it with a DataSet, DataTable, or DataRow, then an easily transferable format is best. That is, a format that directly translates to the desired format, such as a DataRow.
First, let's take a look at structures and classes since they can have properties, methods, and constructors. There are some differences, however, which you can read more about in Moving to VB.NET: Strategies, Concepts, and Code by Dan Appleman (APress, 2003). Now let's take a look at some practical things I've discovered about structures and classes.
Structures are great because they also behave like lightweight classes since they sit on the stack instead of the heap, as long as you use value types. A simple structure looks like this:
Public Structure SomeData
    Dim Name As String
    Dim Description As String
End Structure
The structure is used like this:
Public MyStuff As SomeData
You can also use and return a structure from a function as shown in the following code snippet:
Public Function DoSomething(ByVal Name As String) As SomeData
    With MyStuff
        .Name = Name
        .Description = "Good stuff"
    End With
    Return MyStuff
End Function
As you can see, the function loads the structure with data, then returns it from the function.
Now, let's call the function from another application, in fact from two different applications:
Dim oMyClass As New SomeComponent.Class1()
Dim MyStuff As SomeComponent.Class1.SomeData

MyStuff = oMyClass.DoSomething(GetUserName)
txtDescription.Text = MyStuff.Description
txtName.Text = MyStuff.Name
oMyClass = Nothing
This code returns the name of the current user and the description baked into the class. Now let's call this method from a Web application. This also works just fine. Until, that is, you put the component in COM+. Then you will get an error message stating that the class is not marked for serialization. You can resolve this by adding the serialization attribute to the class, like so:
<Serializable()> _
    Public Class Class1
That solves that problem. So far so good. I'm building a multitier application for a client and the application uses structures, arrays, classes, datasets, and more at different points. In one case, I combine both structures and databases by creating a structure that contains a dataset and some other pieces of information.
The following structure can hold a DataTable and a string. You can pass this around with the data from SQL Server™ and with other data as well:
Public Structure CustomerStuff
    Dim MoreInfo As String
    Dim dt As DataTable
End Structure
The function that returns this structure is shown in Figure 1. RunSQLWithDataSet is in the downloadable sample at the link at the top of this article.
Function ReturnSomedata() As CustomerStuff
        Dim custstuff As CustomerStuff
        Dim ds As DataSet
        Const ConnectionString = _
            getTrustedConnection()
        ds = RunSQLWithDataSet( _
            "Select * from customers", ConnectionString)
        custstuff.dt = ds.Tables(0)
        custstuff.MoreInfo = "This was really cool"
        Return custstuff
    End Function
Using the new method is just like using the other one:
Dim oMyClass As New SomeComponent.Class1()
Dim MyCustomer As SomeComponent.Class1.CustomerStuff

MyCustomer = oMyClass.ReturnSomedata
txtDescription.Text = MyCustomer.MoreInfo
      DataGrid1.DataSource = MyCustomer.dt
      oMyClass = Nothing
As you can see, the structure provides a nice way to handle multiple types of data in one place. This solves the problem of passing back data returned from a function that has more than one return type. This approach is simpler than trying to create a class that holds the DataSet along with the other data. It's also simpler than trying to extend the DataSet itself to hold the additional data.
Now for the drawbacks associated with structures. I ran into two different problems. First, structures do not support events. If you try to use events in a structure, nothing happens when you run the app. So, classes rule in this regard. Second, I had a problem with structures and Visual Studio® .NET. I created a data library that contains a function similar to the one you just saw that returns a structure. It works fine when I call it from the client, so I thought it would be safe to put the structure in a separate component that could be referenced by the client and the data library. This would allow both the data library and UI to reference the third component. When I tried this approach, Visual Studio .NET kept telling me to add a reference to the project for the assembly containing the structure. The trouble was I had already added this reference! But the code would not compile. So I ended up putting the structure in the data library and letting both the middle tier and the UI reference it. It works, but not quite as cleanly as I had hoped.
Now, let's take a look at using classes to hold data. It's worth mentioning that both classes and structures can be bound to controls to make your life much easier. This makes it very simple to set up a control once and link it to a datasource for good. Since they are both synchronized, you don't have to worry about updating one or the other. For more information on data binding, see Billy Hollis's article, "Not Your Father's Data Binding".
Let's consider a simple example where you need to work with customer data. You could put this data into either a structure or a class. What's the difference? Well, that depends on what you want to do with the data. If you want to wire the data to controls and make your life easy, then classes are a good choice because they can fire events, as shown in Figure 2.
Public Class Customer
    Private privateCustomerID As String
    Private privateCompanyName As String
    Private privateContactName As String

    Public Event CustomerIDChanged As EventHandler
    Public Event CompanyNameChanged As EventHandler
    Public Event ContactNameChanged As EventHandler

    Public Property CustomerID() As String
        Get
            Return privateCustomerID
        End Get
        Set(ByVal Value As String)
            privateCustomerID = Value
            RaiseEvent CustomerIDChanged(Me, New EventArgs())

        End Set
    End Property

    Public Property CompanyName() As String
        Get
            Return privateCompanyName
        End Get
        Set(ByVal Value As String)
            privateCompanyName = Value
            RaiseEvent CompanyNameChanged(Me, New EventArgs())
        End Set
    End Property

    Public Property ContactName() As String
        Get
            Return privateContactName
        End Get
        Set(ByVal Value As String)
            privateContactName = Value

            RaiseEvent ContactNameChanged(Me, New EventArgs())
        End Set
    End Property

    Sub Reset()
        CustomerID = ""
        CompanyName = ""
        ContactName = ""
    End Sub
End Class
There are two important features of this simple class. First, the events that signify (such as CustomerIDChanged) are fired whenever a property is modified. The data binding architecture listens for these events and when one fires, it causes the data binding to resynchronize, reloading the controls. Your code just needs to raise the event when you change a property.
This class shows another important feature. In the application I was building, I needed to reset the class and have this action zero out or reset the bound controls. I tried recreating the instance of the class like this:
Dim CurrentCustomer As New Customer()
That didn't work. I finally hit on an elegant solution: a "Reset" method which can be called any time an app needs to refresh the class. Calling Reset will automatically force all bound controls to refresh to the correct state, clearing the form for a new entry.
Now let's turn to DataSets for a minute. I'm going to call the Update method of the SQLDataAdapter and pass it a typed DataSet. No problem, right? Well, not so fast.
Let's look at a sample. This function returns a DataSet with customer data by making a call to the RunSQLWithDataSet function as shown in the following code:
Function RetrieveCustomerContacts() As DataSet
Dim ds As DataSet
ds = RunSQLWithDataSet("Select CustomerID, " & _
    " CompanyName, ContactName from customers", _
    ConnectionString, "Customers")
        Return ds
End Function
The last parameter to RunSQLWithDataSet specifies the name of the table returned in the DataSet. This is very important, as you'll see in a moment. The client application uses a typed DataSet, which is loaded via the Form_Load event of the Windows® Form with the following code:
Dim oData As New SomeComponent.Class1()
Dim ds As DataSet

ds = oData.RetrieveCustomerContacts
CustomerContactInfo1.Merge(ds.Tables(0))
The tricky part of this code is the last line, which calls the Merge method of the typed DataSet. This takes the DataSet returned from the function and merges it with the Customers table of the typed DataSet. The trick is that the schema and the name of the untyped table must match or the Merge will not work as intended; the DataSet table will be added to the DataSet as a new table, instead of being merged with the Customers table.
Let's assume you have everything named correctly and it all works as expected. As you continue coding, at some point you need to change the typed DataSet. In my example, I'd like to change it by adding a string field to reflect a new field that exists in the database. The only problem is that the field in the database is an integer. If you run this code you'll get a run-time error on the Merge method. But that problem is caught pretty easily.
What happens if you modify the typed DataSet and then try an update when one of the datatypes is incorrect? You may get an error such as "Input string in incorrect format." I got this error and it drove me nuts because the typed DataSet was complex, having 25 elements or so. The error message doesn't tell you where the error occurred. A Google search for the error string was of no use. I finally found the error by printing the typed DataSets schema and comparing it field-by-field with the tables schema. I found a discrepancy where the DataSet element and the corresponding field in the table did not match, I fixed the typed DataSet and I tried it again. This time it worked.
As mentioned earlier, there are many ways to move data around in an application, but each application's needs may be different. It's a good idea to prototype different parts of your code, working out the kinks of transferring data along the way. Then you can devise standards for different methods while adding to your own knowledge base of potential pitfalls.

Send your questions and comments for Ken to  basics@microsoft.com.


Ken Spencer works for 32X Tech (http://www.32X.com), where he provides training, software development, and consulting services on Microsoft technologies.

Page view tracker