Welcome to Windows Communication Foundation (WCF)
Top Tasks :

WCF Team Bloggers

Browse by Tags

All Tags » Answers » Serialization   (RSS)

  • Serializing XML to XML

    How should I represent raw XML content in a contract? It seems like it would be really easy to have within the large blob of XML that makes up a message, a small blob of XML. However, it's more challenging to deal with that situation than you might expect because that small blob of XML has to be handled unlike everything else. With most contracts you can chew along the message and place each of the resulting bits in its proper place. When trying to preserve the raw XML though, you have to know when not to chew. In your contract you should use XMLSerializer formatted fields to turn off most of the unnecessary thinking regarding the XML content. Then, XmlSerializer knows about special handling for XmlElement and XmlAttribute to complete the mapping between pieces in the message and fields in your type. These two types work under the covers with XmlSerializer even though they don't implement the standard contract for serialization. With Orcas, you can also use the new XElement type that is defined by XLinq. XLinq doesn't have any deep integration with XmlSerializer but XElement directly implements the IXmlSerializable contract to make things work. Next time: Mapping Client Certificates Read More...
  • Generating Types with Lists

    I have a data contract that contains a collection type but the generated proxy appears as an array. How can I make the proxy use a collection type as well? I've talked in the past about how the representation of a type in metadata is decoupled from the CLR representation of a type in the service. For example, if I have a data contract that uses a List: [DataContract] class Data { [DataMember] public List< string > data; } Then, the metadata representation of this data contract is actually described as an array because arrays are the only primitive type for collections in schema. < xs:schema xmlns:tns ="http://schemas.datacontract.org/2004/07/" elementformdefault ="qualified" targetnamespace ="http://schemas.datacontract.org/2004/07/" xmlns:xs ="http://www.w3.org/2001/XMLSchema" > < xs:import namespace ="http://schemas.microsoft.com/2003/10/Serialization/Arrays" > < xs:complexType name ="Data" > < xs:sequence > < xs:element xmlns:q1 ="http://schemas.microsoft.com/2003/10/Serialization/Arrays" minoccurs ="0" name ="data" nillable ="true" type ="q1:ArrayOfstring" > </ xs:element > </ xs:sequence > < xs:element name ="Data" nillable ="true" type ="tns:Data" > </ xs:element > </ xs:complexType ></ xs:import ></ xs:schema > However, just as the metadata representation isn't coupled to the service, the metadata representation also isn't coupled to the client. You can on the client generate proxies with any type for this collection that similarly can be serialized or deserialized to an array. The mechanism for doing this with svcutil.exe is the /ct switch. The /ct switch, which stands for collectionType, allows you to give a qualified type name that is used for collection data types when generating a proxy. As an example, to get back to the original collection class used by the server, the proxy would need to be constructed using /ct:System.Collections.Generic.List`1 as the option passed to svcutil.exe. However, you could leave the proxy using arrays or provide a different collection class such as /ct:System.Collections.ObjectModel.Collection`1 and with any of these configurations the proxy would be able to exchange messages with the server. Next time: Setting the Configuration Name Read More...
  • One Shot Serialization

    Why do some serialization errors when sending a response not result in a fault being returned to the client? In the typical service operation, sending a response is comprised of returning the appropriate information from the service method to construct a message. You might think of that response as a single operation but performing the response is divided up into many different acts. As an example of a division you could make, one way to split a response into separate acts is to say that there is an act of thinking about whether to respond and what the response contains, an act of constructing the response, and an act of transmitting the response. There is a moment in time during those acts in which the system moves from thinking about a response to actually carrying out the response. Because there are many different ways to divide the operation into a series of acts, that moment in time does not always make up a clear line separating one part of the system from another. However, if you get to the point where you've started carrying out the response, then you've attempted to respond. As an example in WCF terms, RequestContext.Reply is one key point at which the act of responding is realized. There are a variety of different messaging patterns; the ones that you should be familiar with are the one-way, request-reply, and duplex patterns. One-way patterns don't have a response so we can ignore those in this discussion. Request-reply patterns have the property that for any given request there can only ever be one response. If you think about the act of responding now, then there is a point at which your single attempt to respond has fail. This point is totally divorced from what takes place on the wire. It instead is an internal artifact of how the particular system divides the response into acts. A failure before that point would permit an error response to be sent instead while a failure after that point means that no response can ever be sent. Next time: Hosting Identity Read More...
  • Differences in Enum Serialization

    Why does adding an enum parameter to an operation cause the proxy to explode into message contracts? This was a question asking why the following perfectly ordinary operation contract caused svcutil.exe to spit out some really ugly code. [OperationContract] void Foo(EnumType e); Getting started debugging the problem was fairly easy because svcutil left a nice comment explaining what went wrong during code generation. // CODEGEN: Generating message contract since element name e from namespace http://tempuri.org/ is not marked nillable This was a completely accurate statement because when I checked the schema for the operation, the operation parameter was not marked nillable. However, it didn't help at all to explain why this was happening. < xs:element name ="Foo" > < xs:complexType > < xs:sequence > < xs:element xmlns:q1 ="http://schemas.datacontract.org/2004/07/" minOccurs ="0" name ="e" type ="q1:EnumType" /> </ xs:sequence > </ xs:complexType > </ xs:element > A brutal way to solve the problem would be to change the operation parameter from EnumType to EnumType? to force it to be nillable. Clearly though, something more fundamental was wrong because when I checked the schema for EnumType it was not what I expected. < xs:simpleType name ="EnumType" > < xs:restriction base ="xs:string" /> </ xs:simpleType > The error wasn't that EnumType was passed as a string (it's relatively common to represent an enumeration using the names of the values), but that the type didn't actually define any values at all. I would have expected to see under the restriction a list of enumeration values for this type. This was also apparent in the generated proxy. The proxy was using raw strings rather than a nice enumerated type because the restriction had no values defined. The problem was solved by looking at the definition of EnumType. [DataContract] public enum EnumType { ValueOne, ValueTwo } By applying a DataContract attribute, the default serialization contract for the enum was replaced by a contract that didn't include any of the values as members. The default contract would have included all of the values. Specifying a DataContract attribute is only needed when customizing the serialization contract, such as when you only want to expose a subset of the enumeration values. Removing the spurious DataContract attribute fixed the schema problems and allowed svcutil to generate proxies with a nice enumeration type. Read More...
  • Producing Typed Messages

    How do typed messages get created from an object that has a message contract? There seem to be a lot of examples that talk about how messages get produced when they're described by data contracts but relatively few descriptions of the equivalent process for message contracts. There's really nothing complicated or magical here so let's go through it. I'll start with a message that I want to describe with a message contract and then build the contract class. < s:Envelope xmlns:s ="http://www.w3.org/2003/05/soap-envelope" > < s:Header > < h:version xmlns:h ="http://mycorp.com" > 1 </ h:version > </ s:Header > < s:Body > < name xmlns ="http://mycorp.com" > Microsoft </ name > < address xmlns ="http://mycorp.com" > 1 Microsoft Way </ address > </ s:Body > </ s:Envelope > There's a message header whose type is an integer and two body members whose types are strings. This is a pretty easy message to describe although I have to change the settings for the wrapper and namespaces to get the structure to match. I apply an order to the body members because the default would reverse them. [MessageContract(IsWrapped= false )] class MyMessage { [MessageHeader(Namespace = "http://mycorp.com" )] public int version { get; set; } [MessageBodyMember(Namespace = "http://mycorp.com" , Order = 1)] public string name { get; set; } [MessageBodyMember(Namespace = "http://mycorp.com" , Order = 2)] public string address { get; set; } } Now I can use the TypedMessageConverter class to go between the message contract and a Message object. MyMessage record = new MyMessage(); record.version = 1; record.name = "Microsoft" ; record.address = "1 Microsoft Way" ; TypedMessageConverter converter = TypedMessageConverter.Create( typeof (MyMessage), null ); Message message = converter.ToMessage(record, MessageVersion.Soap12); Console.WriteLine(message.ToString()); message.Headers.Clear(); message.Headers.Add(MessageHeader.CreateHeader( "version" , "http://mycorp.com" , 2)); MyMessage record2 = (MyMessage)converter.FromMessage(message); Console.WriteLine(record2.version); Console.WriteLine(record2.name); Console.WriteLine(record2.address); I changed the version header for the return trip just to prove that there's no cheating going on. I gave an explicit message version when creating the message because otherwise I would have gotten SOAP 1.2 with WS-Addressing 1.0. My sample message didn't have any addressing information so I Read More...
  • Differences in Guid Serialization

    Why do the guids in my contract turn into strings when generating a client? You're probably mixing different types of serializers between the client and service. There's nothing wrong with this and the generated client will work correctly but you don't get the user-friendly types. To see why, let's look at the metadata. A guid in a contract with the DataContractSerializer generates a type in the http://schemas.microsoft.com/2003/10/Serialization/ namespace that looks like this: < xs:element name ="guid" nillable ="true" type ="tns:guid" /> < xs:simpleType name ="guid" > < xs:restriction base ="xs:string" > < xs:pattern value ="[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}" /> </ xs:restriction > </ xs:simpleType > On the other hand, a guid in a contract with the XmlSerializer generates a type in the http://microsoft.com/wsdl/types/ namespace that looks like this: < xs:simpleType name ="guid" > < xs:restriction base ="xs:string" > < xs:pattern value ="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" /> </ xs:restriction > </ xs:simpleType > These generated types are needed because a guid is not a primitive type. DataContractSerializer came after XmlSerializer so it recognizes both definitions but XmlSerializer has to rely on the schema when it sees a DataContractSerializer guid. Since the schema is based on a string type, the generated client field is a string. The same thing happens with other serializers that don't know how to map a particular schema pattern to a user-friendly type. Next time: TCP Throttling Read More...
  • Collections without CollectionDataContract

    In the article about serialization conflicts , one of the points mentioned was that CollectionDataContract doesn't let you add non-default data members. How do I format a collection that contains data members? CollectionDataContract is automatically being added even if I don't want it. The trick is that CollectionDataContract is automatically applied to the default collection implementations rather than to all collections. That means that if your class is a List of T then you'll get the automatic CollectionDataContract behavior. If your class is an IList of T then you can choose to decorate the type with normal data contracts. This subtle distinction allows you to save the day. Convert your collection type to implement the corresponding interface and delegate all of the calls to a concrete implementation of the collection that you keep as a member variable. Then, you can figure out how to serialize that member variable, which gives you full control over how the list elements mix together with the other data members. Next time: Printing Flexible Message Headers Read More...
  • Resolving Conflicts in Serialization

    DataContractSerializer supports multiple serialization mechanisms. If more than one serialization mechanism is specified for the same type, which one gets used? Experimentation is the easiest way to figure out what happens. I'll look at different combinations of the XML serializer, the data contract serializer, and the "collection-based" data contract serializer, which is the default mechanism for the concrete collection classes. Let's start with a base interface that defines a member for the type. public interface IFoo { string data { get; set; } } Now, let's apply various combinations of serialization mechanisms to implementations of the base interface. I'll start with each of the serializers by themselves and then each of the legal combinations. Data contracts and collection data contracts can't be used at the same time so that pairing isn't possible as well as trying to use all three serialization mechanisms at once. Here's a quick test program to run through the combinations. public class Program { [DataContract] public class FooDataContract : IFoo { [DataMember] public string data { get; set; } } [Serializable] public class FooSerializable : IFoo { public string data { get; set; } } [CollectionDataContract] public class FooCollection : List< int >, IFoo { [DataMember] public string data { get; set; } } [Serializable] [DataContract] public class FooSerializableDataContract : IFoo { [DataMember] public string data { get; set; } } [Serializable] [CollectionDataContract] public class FooSerializableCollection : List< int >, IFoo { [DataMember] public string data { get; set; } } static void Main( string [] args) { using (XmlTextWriter writer = new XmlTextWriter(Console.Out)) { foreach (Type type in typeof (Program).GetNestedTypes()) { IFoo foo = (IFoo)type.InvokeMember( null , BindingFlags.CreateInstance, null , null , null ); foo.data = type.Name; DataContractSerializer serializer = new DataContractSerializer(type); writer.WriteString(type.Name); writer.WriteWhitespace( "\n" ); serializer.WriteObject(writer, foo); writer.WriteWhitespace( "\n\n" ); } } Console.ReadLine(); } } That gives us a set of outputs to inspect to see what serializer won. FooDataContract <Program.FooDataContract xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">< data >FooDataContract</ data ></Program.FooDataContract> FooSerializable <Program.FooSerializable xmlns:i="http://www.w3.org/2001/XMLSchema-instance" Read More...
  • Serialization and Types

    How does a DataContract type get initialized on the server? When I change the constructor for the type, nothing happens. Older serializers relied on calling the parameter-less constructor to initialize the type when deserializing data. Data contract types have all of the data members initialized to the default values without a constructor being called. However, you can still introduce callback hooks into the serialization process by decorating methods on your data contract type with attributes. Here's a sample program that shows you exactly what goes on. using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.Runtime.Serialization; [DataContract] public class Data { [DataMember] public int a; [OnDeserialized] void OnDeserialized(StreamingContext c) { Console.WriteLine( "OnDeserialized: {0}" , a); a = 1; } [OnDeserializing] void OnDeserializing(StreamingContext c) { Console.WriteLine( "OnDeserializing: {0}" , a); a = 2; } [OnSerialized] void OnSerialized(StreamingContext c) { Console.WriteLine( "OnSerialized: {0}" , a); a = 3; } [OnSerializing] void OnSerializing(StreamingContext c) { Console.WriteLine( "OnSerializing: {0}" , a); a = 4; } } [ServiceContract] public interface IService { [OperationContract] void Method(Data d); } public class Service : IService { public void Method(Data d) { Console.WriteLine( "Method: {0}" , d.a); } } class Program { static void Main( string [] args) { string address = "http://localhost:8000/" ; Binding binding = new BasicHttpBinding(); ServiceHost host = new ServiceHost( typeof (Service)); host.AddServiceEndpoint( typeof (IService), binding, address); host.Open(); ChannelFactory<IService> factory = new ChannelFactory<IService>(binding); factory.Open(); IService proxy = factory.CreateChannel( new EndpointAddress(address)); Data d = new Data(); d.a = 5; proxy.Method(d); factory.Close(); host.Close(); Console.ReadLine(); } } You can try running the program to see the value of the data member at various points in time. If you're still confused, here's exactly what's going on. The data member on the client is set to 5. OnSerializing is called and changes the data member from 5 to 4. The service is called. OnSerialized is called and changes the data member from 4 to 3. The service doesn't see this because the data has already been sent. This only changed the value of the data member on the client. The service initializes the type to its default value, which for the data member is 0. OnDeserializing Read More...
  • Serializing UniqueId

    Why can't UniqueId be serialized? Data contracts only have native support for a limited set of types. If you use a type that is not in this native set, then you'll get an exception that the data contract is invalid unless you decorate the type with attributes that explain how the type should be serialized. Adding attributes requires you to change the type, which means that there are going to be many types in the world that can't be used with data contracts. This includes types in the framework. System.Xml.UniqueId is an example of a type that lacks native support in the data contract implementation. It doesn't mean that there's anything wrong with that type, just that it can't be used with the data contract serialization mechanism. Other serializers will still work with the UniqueId type. For instance, XmlDictionaryWriter has native support to turn a UniqueId into a string, so the UniqueId type can be used with XML serialization. Next time: Service Contract Generation Read More...
  • Data Contract and Message Contract

    I have an existing web service that I need to replace with a WCF web service. How do I choose between using a data contract and a message contract? There are actually three choices to consider for describing the messages that your service uses: data contracts, message contracts, and XML serialization. You will be forced to use XML serialization in some cases because you have an existing message format with precise specification of XML elements and attributes that you need to replicate. In these cases, it may simply be impossible to duplicate this exact XML schema with a message or data contract-based description, forcing you to use XML serialization to describe the messages. However, let's assume that the existing message format is not so unreasonable and you have a choice between the various options for describing messages with contracts. How do you choose between data contracts and message contracts? The choice may not always seem clear if both types of contracts are capable of describing your messages. A rule of thumb though is that data contracts are generally portable between different kinds of XML encodings, making this option preferable if you might choose to project the Infoset differently in the future. Message contracts are more limited in the projections that they can support but are reasonably adept at mimicking the most common types of XML messages produced today. Therefore, there is a preference to use data contract, followed by message contract and XML serialization. However, the ability to adapt to a preset form is ranked in the reverse order. When you're required to conform to an existing message layout, you are more likely to be forced to use message contracts. When you are designing new message layouts, you almost always want to use data contracts. Next time: Message Disposal Read More...

Copyright © 2006 Microsoft Corporation. All Rights Reserved. | Terms of Use | Privacy Statement | Contact Us