]> Visual Studio Service reference collection type 🌐:aligrant.com

Visual Studio Service reference collection type

Alastair Grant | Monday 11 May 2020

C# Generics are a wonderful way of dealing with collections of data; arrays are cumbersome and clunky to work with quickly.  Which why it irks me so much when I add a SOAP reference to a Visual Studio project to find that collections materialise themselves as good old-fashioned arrays.  Such as a string[] array, instead of a List<string> collection.

Fortunately for us, there is an easy* way of changing this behaviour.  When adding (or configuring) your web-service reference, the advanced box has a drop-down for "Collection type".  It will default to System.Array; you can change this to System.Collections.Generic.List and your service will now use List<T>.

* But it doesn't

I noticed this option when we all moved away from the .NET 2.0 Web Reference dialogue.  But it has never worked for me.  It doesn't bother me much, but today it did, and I went down the rabbit hole of trying to work out why.

When creating a stand-alone WCF service that uses a List<T> collection, it materialises as expected in Visual Studio's reference.cs file.  So what is the difference between a WCF generated WSDL and another random WSDL?  The crux of the issue is the serialiser that is used by Visual Studio to generate the proxy classes for the service.  There is the full-blow XmlSerializer and then there is lighter-weight DataContractSerializer; it's the latter that is needed for fancy things like Generics.

Fixing your service WSDL

In order to get Visual Studio to use the DataContractSerializer instead of XmlSerializer, the WSDL needs to be compatible - which is actually a fairly tall ask as it doesn't support a lot of things out of an XSD, including common things like attributes.  Don Smith comes to the help with a blog post on Handcrafting WCF-friendly WSDLs.

The summary is though:

  • Your XSD must not make use of:
    • Ref'd types
    • Attributes
    • Groups
    • Choices
    • Any
    • All
  • Your data types must be nillable
  • There needs to be an additional wrapper schema for all schemas that defines the messages, root elements must be named <Operation> and <Operation>Response and just import the actual XSD and implement the actual message content type.  The namespace for this schema must match the webservice namespace.
  • Message parts must be named "parameters"

If these considerations aren't taken when constructing the WSDL, then they won't be DataContractSerializer friendly, and thus you won't get some handy programming features generated in the client.

Trade off

The question is, is it worth it?

Probably not as it's trivial to convert List<T> into an array with .ToArray(), as well as generate new Lists from an array.  The cost of DataContractSerializer is high in terms of schema design, not being able to use attributes being the most glaring one.

As with all things, the most appropriate approach should be taken for the task in hand.  Smaller services can get away without having to implement the full extend of the XSD flexibility, so it might be worth keeping the above in mind.  For more complex services, it's probably counter-productive to compromise the schema design for the sake of slicker Visual Studio integration.

It is a shame though that the svcutil program doesn't handle using generic types for collections, as it will happily process them if you manually use them with the serialiser.

Breaking from the voyeuristic norms of the Internet, any comments can be made in private by contacting me.