Export (0) Print
Expand All
Expand Minimize

Web Services Interoperability Guidance (WSIG): IBM WebSphere Application Developer 5.1.2

 

Simon Guest
Microsoft Corporation

September 2004

Applies to:
   Microsoft .NET Framework 1.1
   Microsoft Visual Studio .NET 2003
   IBM WebSphere Application Developer (WSAD) 5.1.2

Summary: Predicting whether Web services interoperability between two platforms is going to work is sometimes difficult. Simon Guest shares recommendations for Web services interoperability between the Microsoft .NET Framework 1.1 and IBM WebSphere Application Developer (WSAD) 5.1.2. (19 printed pages)

Contents

Web Services Interoperability: "Is It Going to Work?"
About the Recommendations
IDE Recommendations
"On the Wire" Recommendations
Conclusion

Web Services Interoperability: "Is It Going to Work?"

It was just after a presentation I'd given at TechEd 2003 in Dallas. The topic was Interoperability with Web services and I was standing at the podium, taking questions from the attendees.

"I have a question," remarked one of the attendees. "One of our major applications is written using IBM WebSphere Application Developer." I nodded in acceptance. "I'm looking to build an application in .NET and interoperate with IBM WebSphere using Web services." There was a pause. "Is it going to work?"

A great question, I thought. I've found that there are two ways to answer these types of questions. If I've had experience with the said platform, then chances are I can talk through some of the recommendations and best practices that I've come across. If I've not had such experience, then I tend to allude to more general guidelines, and start talking about vendor commitment and the WS-I.

This conversation with the attendee got me thinking. How can we really test Web services interoperability between two platforms? Something that may work for one may not work for another. This is also going to change based on the types of data being passed across the wire.

To try and answer the "is it going to work" question, after the presentation I created a set of unit tests—both in NUnit (for .NET) and JUnit (for Java). These tests were designed to simulate common operations between .NET and WebSphere. For example: Passing a message with a Boolean, then a String, then a Long, then a Float. As the tests moved on, they got increasingly complex. Create an array. Nest types within types. Include some null values.

The interesting outcome of the tests is not how well each of the platforms does; rather, it raises the question: What guidance can be extracted based upon the findings? This article is designed to do exactly that. Based on the experience of running the tests, the goal of this document is to share recommendations for Web services interoperability today between the two platforms. The platforms that this article covers are Microsoft .NET Framework 1.1 and IBM WebSphere Application Developer (WSAD) 5.1.2.

About the Recommendations

I've divided the recommendations up in to two sections: IDE Recommendations and "On the wire" Recommendations.

IDE Recommendations covers recommendations for using either Visual Studio .NET 2003 or IBM WSAD 5.1.2 in order to create interoperable Web services. Many of the recommendations will cover the generation of client proxies for both platforms and show examples where this applies. This section is not designed as an exhaustive run through of each of the IDEs, but instead focuses on specific issues that were raised during the tests.

The "On the Wire" recommendations section looks at situations where one platform was expecting a certain value, and the other platform may have sent something else – implying some type of wire compatibility issue between the two. For this section, the purpose of this article is to highlight the issue and offer any recommendation for workarounds.

Finally, through customer and partner feedback, I hope that this becomes a living set of recommendations that can be updated with new advice that I may have missed or alternatives to the guidance proposed.

IDE Recommendations

The recommendations listed in this section cover IDE (or design time) recommendations. They are in no particular order of priority, but some do follow sequentially. Each of the recommendations covers the platform it applies to, an example scenario and the actual recommendation itself.

Recommendation: Correctly Handle .NET Web Service Namespace to Package Mappings

Applies To: Client written in IBM WSAD 5.1.2 calling Web service in .NET.

Scenario: Imagine two Web services, both written in .NET. The first Web service is part of a Customer Relationship Management (CRM) service and is used to create and maintain customers. The service has a method similar to the following:

public Response CreateCustomer(Customer customer)

The namespace for this Web service is http://myorg.org/services/crm

The second Web service is used to display current orders for a customer. It has a method signature that looks as follows:

public Orders GetOrders(Customer customer)

It has been decided that the namespace for this Web service is http://myorg.org/services/purchasing.

When creating a Java Web Services Client in IBM WSAD 5.1.2, the IDE defines the package based on the domain portion of the namespace. The domain portion of the namespaces for these two Web service methods is http://myorg.org, therefore the package name is org.myorg.

IBM WSAD 5.1.2 defines the class name for each Web service based upon the name of the ASMX file (for example, Service1.asmx would result in a proxy class called Service1.java).

In our example, let's imagine the first Web service was exposed using Service1.asmx. Based on the namespace and file name, the data types and proxy files will be created under the org.myorg structure. Within the IDE, this may look similar to Figure 1.

ms998272.wsi-interop-01(en-us,MSDN.10).gif

Figure 1. Namespace structure created in IBM WSAD 5.1.2

Let's imagine however that the second Web service also has the same filename (Service1.asmx). Even though the two Web services may have very different URLs, because the domain portion of the namespace and the filename are the same, this causes a conflict.

When creating the client proxy for the second Web service, the same package (org.myorg) will be used. Because the Service1.asmx file has the same name as the first Web service, all of the client proxy files (Service1*.java) will be in conflict.

ms998272.wsi-interop-02(en-us,MSDN.10).gif

Figure 2. Generated Proxy Files in Conflict

As shown in Figure 2, after creation of the proxy, the original Service1.java, Service1Locator.java, Service1Soap.java, Service1SoapProxy and Service1SoapStub files remain bound to the first Web service. In essence, the second client proxy never gets created.

Recommendation:

To overcome this you can do one of three things:

  1. Change the name of the ASMX Web services namespace:

    For two namespaces of http://myorg.org/services/crm and http://myorg.org/services/purchasing, IBM WSAD 5.1.2 will generate proxy files in the sample package (org.myorg). Using different domains for each Web service will correct this.

    For example, http://crm.myorg.org/services and http://purchasing.myorg.org/services will create packages named org.myorg.crm and org.myorg.purchasing respectively. In this instance, there will not be a conflict.

  2. Ensure all ASMX pages have a unique filename:

    The second option is to ensure all of the ASMX files being consumed by IBM WSAD 5.1.2 have a unique name (for example Service1.asmx and Service2.asmx). This will still create the shared package (org.myorg), but the service proxy files will be uniquely named.

    If however, you are using data types with the same names this could still cause problems.

  3. Use the namespace to package mapping in IBM WSAD 5.1.2.

    At the end of the client proxy generation wizard in the IBM WSAD 5.1.2 IDE, you are given the option to define custom mappings for namespace to packages.

ms998272.wsi-interop-03(en-us,MSDN.10).gif

Figure 3. Custom Namespace Mapping in IBM WSAD 5.1.2

This gives you the option of mapping the unique namespace to a correctly named package. As shown in Figure 3, you have the opportunity to add a namespace to package mapping. For this example, the namespace of the first ASMX Web service (http://myorg.org/services/crm) is mapped to a unique package name (org.myorg.crm).

Recommendation: Correctly Handle Namespace for Array Types

Applies To: IBM WSAD 5.1.2 Client calling .NET Web service

Scenario: In a similar scenario to the previous recommendation, again imagine two Web services, written in .NET. The first Web service is used to create new customers. It has a method that looks like the following:

public Response CreateCustomer(Customer customer)

The second Web service is used to display current orders based on a current customer. It has a method signature that looks as follows:

public Orders GetOrders(Customer customer)

As these two Web services both share the same data (the customer), it is possible—and even recommended in the principles of service design—that the schema for the customer is shared between the two services.

In this example, the schema for the customer data type is represented in XSD as follows:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="Customer" targetNamespace="http://myorg.org/types/customer.xsd" 
elementFormDefault="qualified"
xmlns="http://myorg.org/types/customer.xsd" 
xmlns:mstns="http://myorg.org/types/customer.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Customer">
<xs:sequence>
<xs:element name="Id" type="xs:string" />
<xs:element name="Created" type="xs:dateTime" />
<xs:element name="Name" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="Customer" type="Customer"></xs:element>
</xs:schema>

As shown above, the namespace of the customer is http:/myorg.org/types/customer.xsd. Based on this, the xsd.exe tool (a utility in the .NET Framework SDK) has been used to generate the class from this XSD document (xsd.exe /c customer.xsd). This is used for the Web services described above.

In IBM WSAD 5.1.2, when you create the Java proxies for these two Web services, everything works, as shown in Figure 4.

ms998272.wsi-interop-04(en-us,MSDN.10).gif

Figure 4. Proxy Generation in IBM WSAD 5.1.2

org.myorg is used for the shared data types.

org.myorg.crm is used for the CRM service.

org.myorg.purchasing is used for the purchasing service.

The issue arises if the ASMX Web services are changed to use arrays instead of single values.

For example, imagine that the Web services methods are changed from this:

public Response CreateCustomer(Customer customer)
public Orders GetOrders(Customer customer)

To this:

public Response CreateCustomer(Customer[] customer)
public Orders GetOrders(Customer[] customer)

When the java client proxies are regenerated through IBM WSAD 5.1.2, a new class called ArrayOfCustomer is created in the org.myorg package.

ms998272.wsi-interop-05(en-us,MSDN.10).gif

Figure 5. Proxy Generation for Array Types in IBM WSAD 5.1.2

Everything looks to be OK, until you re-run the Java client. When the client runs, one of the .NET Web services is correctly passed the array, where as the other Web service believes it receives a null value. This problem arises because the namespace for the ArrayOfCustomer type is bound to a particular service.

Exploring further, we can see that the generated ArrayOfCustomer_Helper.java class contains static methods that are explicitly bound to a particular Web service:

field.setXmlName(com.ibm.ws.webservices.engine.utils.QNameTable.createQ
Name("http://crm.myorg.org/services", "Customer"));

This therefore breaks the model of sharing schemas between services and we are forced to look at alternative workarounds in IBM WSAD 5.1.2 in order to compensate.

Recommendation:

To overcome the issue of these namespace issues, one of the following options is recommended:

  1. Generate, Refactor, Generate and Refactor:

    During the generation of the client proxy files in IBM WSAD 5.1.2, you can manually move (also known as refactoring) the classes to place them in unique namespaces.

    To do this, clear all of the existing proxy files (to ensure that no old proxy files are left behind), and regenerate the client proxy for the first Web service. This will create the correct set of ArrayOfCustomer values in the org.myorg package.

    Within the WSAD 5.1.2 IDE, right click on the generated types in org.myorg and select Move. Move all of the types to either a unique package, or the package used for the Web service proxy itself: org.myorg.crm

    ms998272.wsi-interop-06(en-us,MSDN.10).gif

    Figure 6. Moving Generated Data Types in IBM WSAD 5.1.2

    Do the same for the second Web service and re-run the client.

  2. Generate with custom namespace to package mapping:

    An alternative to refactoring the classes in the previous step is to again use the Web service namespace to package mapping option at the end of the Java proxy wizard.

    ms998272.wsi-interop-07(en-us,MSDN.10).gif

    Figure 7. Using Custom Mappings to Map the Data Types

    To use this, map the namespace of the XSD type (in this case it is http://myorg/types/customer.xsd) to the package that contains the client proxy files (org.myorg.crm).

For both the options listed above, you will also need to change the client code to reference the correct data type for each proxy. For example:

org.myorg.purchasing.ArrayOfCustomer purCustomers = 
new org.myorg.purchasing.ArrayOfCustomer();
purCustomers.setCustomer(new org.myorg.purchasing.Customer[]{cust2});
proxy.getOrders(purCustomers);

Although the data types are being duplicated, each Web service will now be called using the correct namespace.

Recommendation: Keep Web Services Class Names Unique in WSAD 5.1.2

Applies To: Web services created using IBM WSAD 5.1.2

Scenario: The first recommendation in this article covered how IBM WSAD 5.1.2 has an issue dealing with two ASMX files with the same name. Likewise, Web services that have the same class name in WSAD 5.1.2 can also experience problems. If you are planning Web services in both .NET and IBM WSAD 5.1.2 that share the same names across projects, this could be an important consideration.

To demonstrate this, imagine that you have two Java beans created under the scope of a single project in WSAD 5.1.2, as shown in Figure 8:

ms998272.wsi-interop-08(en-us,MSDN.10).gif

Figure 8. Creating Two Web services with the Same Name

Notice how both beans are in separate packages, but both are called the same class (Service.java).

Right clicking each of these beans within the IDE and selecting Web services->Deploy As Web Service generates a Web service for each bean. This generates an SEI (Service Endpoint Interface) file for each of the classes and additional WebContent files required for the deployment.

The Web services are built correctly, and will compile, but when they are deployed to the WebSphere server, the following error is observed.

[8/12/04 17:25:03:389 PDT] 3ce2077a WebGroup      E SRVE0020E: [Servlet Error]-[org_myorg_crm_Service]: 
Failed to load servlet: java.lang.ClassCastException: org.myorg.crm.Service
   at com.ibm.ws.webcontainer.webapp.WebAppServletManager.loadServlet(WebAppServletManager.java:188)
   at com.ibm.ws.webcontainer.webapp.WebAppServletManager.loadAutoLoadServlets(WebAppServletManager.java:542)
   at com.ibm.ws.webcontainer.webapp.WebApp.loadServletManager(WebApp.java:1277)
   at com.ibm.ws.webcontainer.webapp.WebApp.init(WebApp.java:283)

Only the last Web service with the same name will be deployed. This applies even if the name of the generated WSDL file (Service.wsdl by default) is renamed to something unique.

Recommendation:

It is believed that this is an error with the binding generation during the WebSphere deployment process. To overcome this error, ensure that all Web services (resident under the same project) have unique class names.

If class names must be the same for two or more Web services (for example, you wish to duplicate the setup of several ASMX Web services), the recommendation is to use multiple projects to host these.

Recommendation: Use Lower Case Method Names for Web Services in IBM WSAD 5.1.2

Applies To: Web services created using IBM WSAD 5.1.2

Scenario: Imaging that you are planning a similar suite of Web service methods to run on both Microsoft .NET and IBM WebSphere.

For example:

public Customers GetCustomers() in .NET

public Customers GetCustomers() in IBM WSAD 5.1.2

When you try and deploy a Web service with this method in IBM WSAD 5.1.2 you will get the following message:

java.lang.Exception: WSWS3352E: Error: Couldn't find a matching Java 
operation for WSDD operation "getCustomers" (Debug Info: name:       services/Service

The exception raised indicates that the reflection processes of the service are looking for method names that only start with lower case letters.

Recommendation: If using both Microsoft .NET and IBM WSAD 5.1.2 to generate Web services, you may want to set some standard naming conventions ahead of time based on this recommendation. Doing so may reduce the likelihood of clients calling different cased methods for each Web service. For example:

Method service1.GetCustomers() for .NET

Method service2.getCustomers() for IBM WSAD 5.1.2

Web services created and deployed using Microsoft .NET support method names that start with both upper and lower case letters.

Recommendation: Watch For Booleans When Generating Java Beans from XSD File

Applies To: Web services created using IBM WSAD 5.1.2

Scenario: For generating classes from XSD documents, IBM WSAD 5.1.2 uses the Java Beans for XML Schema wizard. The wizard creates bean methods (getters and setters) from the XSD document.

If the wizard comes across a value of type of xsd:boolean however, the getter method is prefixed by is instead of get. For example:

order.isFulfilled() 
Whereas order.getFulfilled() may have been expected.

Recommendation: This is important to note if you are using any reflective properties from a .NET client that is consuming a Web service hosted using IBM WebSphere.

For the unit tests I had to check whether the method returned a Boolean value and adjusted the call accordingly.

Recommendation: Use compareTo() Method When Comparing Dates

Applies To: IBM WSAD 5.1.2 client calling a .NET Web service

Scenario: Imagine that you have a client created using IBM WSAD 5.1.2 that is consuming a Web service based in .NET. The Web service returns data which contains a xsd:dateTime value.

On the client, this will be deserialized to a type of java.util.Calendar. To validate a date it may be tempting to use:

if (service.getDate() == myOrder.getDate())
{
   //do something
}

Due to potential inaccuracies to how the xsd:dateTime format is passed across the wire and serialized/deserialized, this expression may fail – although the dates look alike.

Recommendation: For accuracy, it is recommended to use the compareTo method in order to compare with a locally held date. Using this method will help prevent any ambiguity between the passed date/time and the local value.

For example:

if (service.getDate().compareTo(myOrder.getDate() == 0)
{
   // do something
}

Recommendation: Use ArrayOf Constructs in IBM WSAD 5.1.2 Clients

Applies To: IBM WSAD 5.1.2 Client calling a .NET Web service

Scenario: Imagine a .NET Web service that contains the following method:

public void Method1(Message[] messages)
{
   //do something with the messages
}

The method accepts an array of messages. When thinking about the IBM WSAD 5.1.2 client proxy, you may believe that you should call the method using the following construct:

Message[] messages = myFactory.createMessages();
service.Method1(messages);

Recommendation:

When the client proxy is generated by IBM WSAD 5.1.2, a new data type called ArrayOfMessage will be created. The Web service has to be called using the following code:

Message[] messages = myFactory.createMessages();

ArrayOfMessage mArray = new ArrayOfMessage();
mArray.setMessageType(messages);  

service.Method1(mArray);

Using this construct will ensure that arrays sent in Web service requests are correctly handled between IBM WSAD 5.1.2 clients and .NET Web services.

"On the Wire" Recommendations

The recommendations listed in this section cover "On the Wire" (or runtime) recommendations. They are in no particular order of priority, but some do follow sequentially. Each of the recommendations covers the platform it applies to, an example scenario and the actual recommendation itself.

Recommendation: Avoid Sending Null Date and Time Values Over Web Services

Applies To: .NET Client and .NET Web service

Scenario: You have a Web service running on IBM WebSphere that returns a date and time. Either through a single method:

public java.util.Date Method1()
{
   return null;
}

Or, a method that returns an object that contains a date and time value:

public OrderItem Method1()
{
   return new OrderItem();
}

public class OrderItem
{
   public long id;
   public java.util.Date created;
}

When this method is consumed by a client in Microsoft .NET, and the date/time value is null (or not initialized), an exception is raised. The exception type is System.FormatException, and the client believes that there is an error is the returned XML file.

Recommendation:

The reason for this error is that in Java, java.util.Date and java.util.Calendar are classed as reference types. In .NET, System.DateTime is considered a value type. As you may know, reference types can be null, whereas value types cannot. In v1.1 of the .NET Framework, there is no understanding of null date and time values.

To overcome this, you can take one of three approaches:

  1. Embed the date/time value in a complex object (as shown above with the OrderItem type). Set the value of complex object to null to indicate a null date/time value. Within the unit tests, this method is proven to work.
  2. Have the IBM WSAD 5.1.2 Web service and .NET client agree on a default value (e.g. 1/1/1900 12.00am) to represent a null value.
  3. Send the date/time as a string across the Web service. Use either a null or empty string to represent a null date.

Recommendation: Avoid Returning Null Arrays from IBM WSAD 5.1.2

Applies To: .NET Client calling IBM WSAD 5.1.2 Web service

Scenario: Imagine the following Web service in WSAD 5.1.2:

public Messages[] Method1()
{
   return null;
}

When the .NET client receives the response from the Web service, it is interpreted as a single element, not a NULL value.

Recommendation:

The recommendation is to avoid returning NULL arrays—or instead return the NULL array as an element of a complex object, which works successfully.

SOAP Trace:

When the IBM WSAD 5.1.2 Web service is called with the above example, it returns the following response:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<method1Response xmlns="http://primitiveArray.wsig.samples.microsoft.com">
<method1Return xsi:nil="true"/>
</method1Response>
</soapenv:Body>
</soapenv:Envelope>

The .NET Client however was expecting the following (this message is correctly sent from a .NET Web service):

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<Method1Response xmlns="http://schemas.wsig.samples.microsoft.com/primitiveArray/NoParamSingleNullReturn"/>
</soap:Body>
</soap:Envelope>

Recommendation: Avoid Returning Empty Arrays or Arrays Containing Nulls from IBM WSAD 5.1.2

Applies To: .NET Client calling IBM WSAD 5.1.2 Web service

Scenario: Imagine the following Web service, created using IBM WSAD 5.1.2:

public Message[] Method1()
{
   Message[] myMessage = new Message[10];
   return myMessage;
}

When the .NET Client receives the array, it is able to traverse through the array, but for each element in the array a default message exists instead of a NULL value. This also applies if the .NET client sends an empty array or array containing nulls to the Web service hosted by IBM WebSphere.

Recommendation:

The recommendation is to avoid return empty arrays or arrays containing nulls from a WSAD 5.1.2 Web service.

SOAP Trace:

The following SOAP response was returned from the IBM WSAD 5.1.2 Web service:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<method1Response xmlns="http://primitiveArray.wsig.samples.microsoft.com">
<method1Return xsi:nil="true" 
xmlns:ns-1108258154="http://xsd.primitivemessages.schemas.wsig.samples.microsoft.com"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
<method1Return xsi:nil="true"/>
</method1Response>
</soapenv:Body>
</soapenv:Envelope>

To correctly interpret this, the .NET client expects the following (this was sent by a .NET Web service):

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<Method1Response 
xmlns="http://schemas.wsig.samples.microsoft.com/primitiveArray/NoParamSingleReturnContainingEmpty">
<Method1Result>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
<BooleanMessageType xsi:nil="true"/>
</Method1Result>
</Method1Response>
</soap:Body>
</soap:Envelope>

Conclusion

In this article you have seen some of the recommendations for achieving interoperability between Web services created using Microsoft .NET Framework 1.1 and IBM WSAD 5.1.2.

Through creating this article, it is apparent that interoperability using Web services developed on the Microsoft .NET Framework 1.1 and IBM WSAD 5.1.2 is most definitely achievable today. The results and observations from running the unit tests confirm this, and this is validated by the number of organizations who are developing applications today that span both platforms.

Overall, the results are testament to how well both Microsoft and IBM have implemented the WS-I Basic Profile 1.0 for their implementations of Web services.

I would like to thank Sarvashrestha Paliwal, Avadh Jain, Nilesh Jain, Sachin Joshi, Anurag Katre, Abhilasha Mishra, Ajay Panditrao, Debasis Patil, and Sachin Patil (all from Tata Consulting Services) for their assistance in creating this article.

 

About the author

Simon Guest is a Program Manager in the Architecture Strategy team at Microsoft Corporation, and specializes in interoperability and integration. Simon holds a Masters Degree in IT Security from the University of Westminster, London, and is the author of the Microsoft .NET and J2EE Toolkit (Microsoft Press, Sept. 2003).

Simon can be reached via his blog at http://www.simonguest.com.

Show:
© 2014 Microsoft