Please click this logo to help me get on their beta program:

Xobni outlook add-in for your inbox








22/6/2005

XPO (and other complex types) in .NET web services

Filed under: General, Programming, .NET, XPO — Oliver Sturm @ 5:43 pm - 3 years, 1 month ago

Recently, there have been several requests in the XPO newsgroup about problems with serialization, in conjunction with ASP.NET. I’m still unclear if these issues all had the same sources, but when somebody approached me personally about this today, I thought I’d just look into the web services problem. Please note that I made these tests on the .NET 2 platform, so there may be differences to .NET 1.1. What’s more, ASP.NET and web services are not something I usually have much to do with, so I may certainly be missing something here and there.

Now, what is the problem? Simple: If you have a web method that returns a type that’s derived from one of the XPO base classes (XPObject or XPCustomObject, doesn’t matter), an exception will be thrown when you try to access the service:

InvalidOperationException: DevExpress.Xpo.XPDeletedObject cannot be serialized
because it does not have a parametless constructor.

(Editor: DevExpress, if you’re reading, how about fixing that message? :-) )

Similarly, if you try to return an XPCollection, the following exception will be thrown:

NotSupportedException: Cannot serialize interface DevExpress.Xpo.IXPSimpleObject.

So, at a glance one could think that XPO is completely incompatible with web services for these simple reasons. Well… not.

IXmlSerializable

Because web services use XML (SOAP) serialisation to transfer data from one point to another, it’s important that any complex data objects you want to transfer must be convertible by the standard mechanisms. The exception that’s shown for the XPObject return type tells us that there’s a problem with one of the types referenced by one of the base classes - the standard mechanism gives up at that point. To enable conversion of the object’s data to XML, we need to override the defaults and provide our own implementation of the XML creation code. Here’s a simple XPO data class that creates its own XML code for serialisation:

public class DataObject : XPObject, IXmlSerializable {
  public DataObject() { }
	
  public DataObject(int index, string strVal) {
    this.index = index;
    this.strVal = strVal;
  }
	
  private int index;
  public int Index {
    get { return index; }
    set { index = value; }
  }
	
  private string strVal;
  public string StrVal {
    get { return strVal; }
    set { strVal = value; }
  }
	
  void IXmlSerializable.WriteXml(XmlWriter writer) {
    writer.WriteElementString("Index", XmlConvert.ToString(index));
    writer.WriteElementString("StrVal", strVal);
  }
	
  void IXmlSerializable.ReadXml(XmlReader reader) { }
	
  XmlSchema IXmlSerializable.GetSchema() { return null; }
}

Now a method that returns an object of type DataObject will render the following nice XML code when invoked via the web service (and the exception will be gone):

<?xml version="1.0" encoding="utf-8"?>
<DataObject xmlns="http://sturmnet.org/">
  <Index>42</Index>
  <StrVal>One entry</StrVal>
</DataObject>
Type information

The main remaining problem with this is that the WSDL code for the web service will still not contain a type definition for the complex type, so on the consuming side access to the data isn’t as easy as on the service side. To provide the web service with type information that can be used for WSDL generation, the object that implements IXmlSerializable must also deploy the XmlSchemaProvider attribute (this is new in .NET 2.0, I think in 1.1 the GetSchema method of the interface should be used, which is deprecated in 2.0). This attribute defines a static method in the class that must add XML Schema information to the schema set used by the XML serialiser. With that in place, the example class looks like this:

[XmlSchemaProvider("XmlSchema")]
public class DataObject: XPObject, IXmlSerializable {
  ...
	
  public static XmlQualifiedName XmlSchema(XmlSchemaSet xmlSchemaSet) {
    XmlSerializer schemaSerializer = new XmlSerializer(typeof(XmlSchema));
    StringReader reader = new StringReader(Resources.DataObject);
    XmlSchema schema = (XmlSchema) schemaSerializer.Deserialize(reader);
    xmlSchemaSet.Add(schema);
	
    return new XmlQualifiedName("DataObject", "http://sturmnet.org/DataObject");
  }
}

The schema itself, which I’m simply loading from a resource in this case, looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="DataObject"
                  targetNamespace="http://sturmnet.org/DataObject"
                  elementFormDefault="qualified"
                  xmlns="http://sturmnet.org/DataObject"
                  xmlns:mstns="http://sturmnet.org/DataObject"
                  xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="DataObject" type="DataObject" />
	
	<xs:complexType name="DataObject">
		<xs:sequence>
			<xs:element name="Index" type="xs:int" />
			<xs:element name="StrVal" type="xs:string" />
		</xs:sequence>
	</xs:complexType>
</xs:schema>

Now the object can pass the important type information on to the WSDL generation process, and on the consumer side a proxy class will be created automatically to deserialise the data from the XML code. Obviously, creating this code for every data class manually would probably be a lot of work. Using the elaborate type information that XPO collects about its data classes, it should be quite easy to implement generic methods that can output reasonable standard XML code and schema definitions for every XPObject. For now, I’m leaving this as an exercise for the reader. :-)

The collection return type

The final issue is that it’s still not possible to have a web method return a complete XPCollection. To work around this, there are two possible solutions:

  1. Create your own collection type, possibly derived from XPCollection, implement IXmlSerializable on that and handle it like a complex type in its own right. This is the most flexible approach, but it’s also a lot of work. Maybe better to
  2. Have the method return a normal array type instead of the complex type. These types work just fine in .NET and they can be handled out of the box by the standard mechanisms.

Using approach (2), a method returning a collection of DataObjects could look like this:

[WebMethod]
public DataObject[] GetData() {
  XPCollection coll = new XPCollection(typeof(DataObject));
  return (DataObject[]) ArrayList.Adapter(coll).ToArray(typeof(DataObject));
}

This works just fine with the XML serialisation support already implemented in the single DataObject, so a list of objects may look like this (in XML, there’ll be a wonderful DataObject[] type in the consumer proxy):

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfDataObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://sturmnet.org/">
  <DataObject>
    <Index>42</Index>
    <StrVal>One entry</StrVal>
  </DataObject>
  <DataObject>
    <Index>52</Index>
    <StrVal>Another entry</StrVal>
  </DataObject>
</ArrayOfDataObject>

So, I hope this will prove helpful - have fun!

Rory Blyth on bad UI design

Filed under: General, Programming, .NET, Software — Oliver Sturm @ 9:40 am - 3 years, 1 month ago

This blog post from Rory Blyth really had me biting the carpet. Although it’s very funny, there are certain serious points to it that really everybody should consider who has to create user interfaces of any kind at all. Great!

15/6/2005

The ?? operator (C# 2.0)

Filed under: General, Programming, .NET — Oliver Sturm @ 12:18 pm - 3 years, 1 month ago

A while ago, I read a tiny note about this in somebody’s blog and I want to start off by apologizing to that somebody because for the life of me I can’t figure out who it might have been - so no reference here. Sorry about that. Anyway, I followed up on the original information and I thought it couldn’t hurt to pull peoples’ attention to this a bit more.

So, the ?? operator: It’s an extension in C# 2.0 (find the specs here, this operator is explained on page 14, then end of chapter 19.5) and they call it a null coalescing operator. Here’s a conditional expression, in three different forms, but with the same meaning:

MyClass anObject;
...
// Variant 1: Using a full if/else clause
MyClass anotherObject;
if (anObject != null)
  anotherObject = anObject;
else
  anotherObject = new MyClass();
	
// Variant 2: Using the ?/: conditional operator
MyClass anotherObject = anObject != null ? anObject : new MyClass();
	
// Variant 3: Using the ?? operator
MyClass anotherObject = anObject ?? new MyClass();

So this should really make the purpose of the operator quite clear: check something for null, return the same something if it’s not null, the given alternative value otherwise.

This functionality is slightly extended where it comes to nullable types. Normally, if both parameters to the ?? operator are nullable types, the return type will be the same nullable type. This doesn’t differ from the behaviour with any other type. But if only the first parameter is a nullable type while the alternative value is not nullable, the result type will be the non-nullable “base” type and the Value property of the nullable will be evaluated if necessary. So this is all valid code:

int? foo = null;
int bar = foo ?? 42;
// bar is now 42
	
foo = 52;
bar = foo ?? 42;
// bar is now 52 because foo.Value has been evaluated
	
int? nbar = foo ?? 42;
// nbar is now 52, but it's also a nullable type because the int has
// been converted back to an int? immediately

2/6/2005

Adding headers to files in a batch

Filed under: General, Programming — Oliver Sturm @ 8:44 pm - 3 years, 1 month ago

Valery just posted a blog article about a tool to insert headers in a bunch of files. I don’t have too much to say about that, but the comment form on the blog didn’t want me to post the following (a server error message about a potentially dangerous form post, lol), so I thought I’d just put it in my own blog instead. Here’s the comment I wanted to post:

Wow! That’s some solution for a tiny problem… How about a small shell script:

#!/bin/sh
	
for file in *.cpp; do
  cat my_new_header > $file.new
  cat $file >> $file.new
  mv -f $file.new $file
done

Certainly not the most elegant solution, but just as certainly it does the job and takes only a few seconds to write when needed.

Video demo of free refactoring for VB.NET

Filed under: General, Programming, .NET — Oliver Sturm @ 8:34 am - 3 years, 1 month ago

A while ago, Developer Express announced the availability of a free version of their Refactor! product for Visual Basic .NET. The official download page is accessible via this Microsoft page.

Now there’s a video available on Channel 9, showing an interview with Mark Miller, the Developer Express chief architect for IDE tools, and Jay Schmelzer, the lead program manager of the Visual Basic team at Microsoft. Mark demonstrates a lot of the functionality of the free Refactor! version, so if you haven’t tried it yourself (and even if you have), definitely go check it out!

Click here for the Channel 9 thread on the video, and click here to start the video right up.

1/6/2005

I’m going to Tech Ed!

Filed under: General, Programming, .NET — Oliver Sturm @ 5:16 pm - 3 years, 1 month ago

This Saturday, I’ll be on my way to Tech Ed 2005 in Orlando. My first Tech Ed, so I’m certain that will be great fun!

I’m sure I’m going to catch a lot of sessions, after all the agenda is huge (and even what’s left in the personal planner still looks intimidating :-) ). I guess I’ll also be spending a lot of time around the Developer Express booth, being a member of their DX-Squad. So in case someone should be looking for me there, you know where to find me :P

Why am I never seeing rats vomit?

Filed under: General — Oliver Sturm @ 5:06 pm - 3 years, 1 month ago

Hm… calculating from the number of times I see any creature whatsoever vomit and considering the relation between the number of rats I usually have any kind of contact with and the number of non-rat creatures I usually have any kind of contact with, I don’t think that’s really a valid question to ask. But this blog article and the pages linked from there, especially this essay explain the scientific reason in great depth. Probably not really necessary to know, but a fun read, somehow :-)

Powered by WordPress
© Copyright 2005-2008 Oliver Sturm