Web Services Enhancements (WSE) 3.0 for .NET serializes a custom data type incorrectly (917506)



The information in this article applies to:

  • Microsoft Visual Studio 2005 Standard Edition
  • Microsoft Visual Studio 2005 Professional Edition
  • Microsoft Visual Studio 2005 Express Edition

SYMPTOMS

Microsoft Web Services Enhancements (WSE) 3.0 for Microsoft .NET serializes a custom data type incorrectly when the following conditions are true:
  • The data type has a property that is marked as an XmlAttribute class.
  • This property has the byte array (byte[]) data type.
When these conditions are true, WSE 3.0 does not serialize the attribute value to an elements attribute. The attribute value is added to the next class property if one exists. This problem occurs in a WSE 3.0-enabled client application or in a WSE 3.0-enabled Web service.

CAUSE

This problem occurs because of a bug in the XmlWriter class implementation. The XmlWriter class is responsible for writing user data to the XmlDocument class. Later, the XmlDocument class is serialized onto a network stream.

WORKAROUND

To work around this problem, use one of the following methods.

Method 1

Change the data type of the user data from the byte array data type to the string data type. Then, write additional code for the client application or for the Web service to convert the byte array to a string and then back to a byte array as needed. To do this, use the Convert.ToBase64String method and the Convert.FromBase64String method.

Method 2

Create a new class in the client application that is derived from the Web service proxy class (the WebService class). In the new class, override the GetWriterForMessage method. The GetWriterForMessage method returns an XmlWriter class implementation. The XmlWriter class implementation delegates all operations except for the WriteBase64 method to the XmlWriter class instance that is returned by the base class. The WriteBase64 method implementation must be delegated to the wrapped writer if the WriteState enumeration is not the Attribute member. Otherwise, the WriteBase64 method should convert the byte array to a string.

The following code sample is an example of the new class and of the overridden methods. For this code sample to compile correctly, you must implement the rest of the XmlWriter class methods.
class WorkaroundMyWebService : localhost.MyWebServiceWse
    {
        public WorkaroundMyWebService(): base() { }

        protected override System.Xml.XmlWriter GetWriterForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize)
        {
            return new XmlWrappingWriter(base.GetWriterForMessage(message, bufferSize));
        }

        class XmlWrappingWriter : XmlWriter
        {
            XmlWriter writer;

            public XmlWrappingWriter(XmlWriter baseWriter)
            {
                if (baseWriter == null)
                    throw new ArgumentNullException("writer");
                this.writer = baseWriter;
            }

            public override XmlWriterSettings Settings { get { return writer.Settings; } }
            public override WriteState WriteState { get { return writer.WriteState; } }
            public override XmlSpace XmlSpace { get { return writer.XmlSpace; } }
            public override string XmlLang { get { return writer.XmlLang; } }
-
            public override void WriteStartDocument()
            {
                writer.WriteStartDocument();
            }

            public override void WriteBase64(byte[] buffer, int index, int count)
            {
                if (this.WriteState == WriteState.Attribute)
                {
                    writer.WriteString(Convert.ToBase64String(buffer, index, count));
                }
                else
                {
                    writer.WriteBase64(buffer, index, count);
                }
            }

           //Implement the rest of the XmlWriter methods
	   //...

        }
    }
Additionally, change the client application to use the following derived proxy class.
localhost.MyWebServiceWse WseWebSvc = new WorkaroundMyWebService();
     string WseResultString = WseWebSvc.AnalyzeMyObject(myobj);
     Console.WriteLine(WseResultString.ToString());

STATUS

Microsoft has confirmed that this is a problem in the Microsoft products that are listed in the "Applies to" section.

MORE INFORMATION

For more information about how to create a proxy class to communicate with a Web service, visit the following Microsoft Developer Network (MDSN) Web site:

Modification Type:MajorLast Reviewed:6/8/2006
Keywords:kbtshoot kbBug kbprb KB917506 kbAudDeveloper kbAudITPRO