Data Integrity in Web Services

Web Services bring with them great possibilities and with these possibilities are some pitfalls.

Abstract

Web Services bring with them great possibilities and with these possibilities are some pitfalls. One such pitfall is passing complex data types to and from Web Services without losing data integrity. The clearest thing to keep in mind when passing objects to Web Services is the data is passed for your object's fields, but the code is not.

What happens when I have an object that my web service passes as a return value?
WSDL does some magic when a programmer creates a referance to your web service. Visual Studio.NET creates wrapper objects around foreign data types.

The struct you create inside your Web Service looks like this:

public struct PersonData
{
private int yearsExperience;
public int YearsExperience
{
get { return yearsExperience; }
set
{
if(value<2) { throw new Exception("You're unemployable!"); }
yearsExperience =
value;
}
}
public String FirstName;
public String LastName;
}

...Which then gets translated into WSDL which looks like this:

<s:complexType name="PersonData">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="FirstName" nillable="true" type="s:string" />
<s:element minOccurs="1" maxOccurs="1"
name="LastName" nillable="true" type="s:string" />
<s:element minOccurs="1" maxOccurs="1"
name="YearsExperience" type="s:int" />
</s:sequence>
</
s:complexType>

... to the client of the web service, Visual Studio creates a wrapper based upon the WSDL that looks like this:

public struct PersonData
{
public int YearsExperience;
public String FirstName;
public String LastName;
}

And to make matters worse, when this struct gets passed to the server with YearsExperience=1 (A value that PersonData.YearsExperience should not have) it will be passed silently and without an exception! The solution to this bug, I mean feature, is to wrap all data that you want passed to and from a web service inside a struct and then in turn a validator class.

The struct is the carrier of the data between the points and the object does all of the range checking required to keep your data clean.

Step 1: Create the Web Service

The web service below is a simple web service that simply passes the struct PersonData back and forth assigning it to a static member. A useful extention of this example is to build up some object-relational mapping between our Person object and a database, but that is beyond the scope of this article.

The areas of note in this object are the PersonData struct and the Person object. Please note that YearsExperience does indeed have an accessor method. Also note that the Person object does a complete range checking on the struct as it is passed in before allowing an assignment.

To start this project go to File->New Project and then choose a ASP.NET Web Service from the selection menu. The complete code listing is below:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
namespace RemoteObjectPasser
{
public class PersonService : System.Web.Services.WebService
{
static Person person;
public PersonService()
{
InitializeComponent();
if(person==null)
{
person =
new Person();
PersonData serviceData =
new PersonData();
serviceData.FirstName="David";
serviceData.LastName="Talbot";
serviceData.YearsExperience=5;
person.CurrentData=serviceData;
}
}
private void InitializeComponent() {}
protected override void Dispose( bool disposing ) { }
[WebMethod]
public PersonData GetPersonData()
{
return person.CurrentData; }
[WebMethod]

public void SetPersonData(PersonData pd)
{
this.person.CurrentData = pd; }
}
//END OF PersonService Object
public struct PersonData
{
private int yearsExperience;
public int YearsExperience
{
get { return yearsExperience; }
set
{
if(value<2) { throw new Exception("You're unemployable!"); }
yearsExperience =
value;
}
}
public String FirstName;
public String LastName;
}
public class Person
{
private PersonData personData;
public PersonData CurrentData
{
get { return personData; }
set
{
if(value.FirstName.Length > 20)
{
throw new Exception("FirstName must be less than 20 characters"); }
if(value.LastName.Length > 20)
{
throw new Exception("LastName must be less than 20 characters"); }
if(value.YearsExperience < 2)
{
throw new Exception("People with less than 2 years exp are unemployable in IT."); }
personData=
value;
}
}
//Other useful methods to operate on a person
}//END OF PERSON OBJECT
}//END of RemoteObject Passer Namespace

Step 2: The Test Client

Although you can create any client you desire for the web service, in this example I have chosen to create a Windows Application. To do so, simply go to File->New Project and choose Windows Application. Drag and drop the items on the form to look something like the figure below.

DataIntegrityInWebSerDT1.gif

Now choose Project->Add Web Referance and in the bottom left of this dialog box choose "Web Referances on Loacal Web Server". Choose the Web Service we created in step one, then click on OK.

Below is the event handler code for the two buttons of the application. The rest of the code required for the application should be autogenerated by the form builder. Also note you'll need to include the namespace of the web service in order to use the wrapper objects. It should look something like "using WindowsApplication1.localhost;", but you can find out the exact namespace from the Class View->localhost->PersonService. Look at the top of this code file and see what namespace VS.NET gave this wrapper.

private void GetterButton_Click(object sender, System.EventArgs e)
{
PersonData pd = ps.GetPersonData();
FirstNameField.Text = pd.FirstName;
LastNameField.Text = pd.LastName;
YearsExperienceField.Text = ""+ pd.YearsExperience;
}
private void SetterButton_Click(object sender, System.EventArgs e)
{
PersonData pd =
new PersonData();
pd.FirstName = FirstNameField.Text;
pd.LastName = LastNameField.Text;
pd.YearsExperience = Int32.Parse(YearsExperienceField.Text);
try
{
ps.SetPersonData(pd);
MessageBox.Show("Person Set");
}
catch(Exception exx) { MessageBox.Show("Error Setting Data:"+ exx); }
}

To drive the point home as to what VS.NET is doing with the web service, double click on the PersonData struct in the ClassView of your application.

DataIntegrityInWebSerDT2.gif

Taking a look around inside the class viewer is an excellent way to find out exactly what kinds of wrappers VS.NET is creating for differant things you might be doing and will generally give you an excellent idea of what to expect from your remote objects.

Conclusion

Web Services are one of the hottest technologies going right now but there are a number of pitfalls that any programmer must be aware of. Data Integrity is important for any object's proper functioning and must be assured or it could corroupt a larger program and generate a very difficult to trace error. By using the techniques in this article you can keep your objects safe and your data assured.