Consider the following Student defintion:
public class Student
{
public Guid Id {get; set;}
public String FirstName {get; set;}
public S
OK, delete the answer for XmlSerializer because you're using DataContractSerializer.
One way you can accomplish this with DataContractSerializer is by use of surrogates. A surrogate basically is a replacement class that you swap in for one of your "real" classes while serializing, deserializing, and creating schemas. You can use this trick to replace your full Student class with a simple StudentId class depending (e.g.) upon the state of some ThreadStatic state variable indicating whether the full or partial student is to be serialized. (I use ThreadStatic in case you might have multiple threads serializing data in parallel.)
Thus your Student class would become something like this:
[DataContract()]
public class Student
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public String FirstName { get; set; }
[DataMember]
public String LastName { get; set; }
}
[DataContract()]
public class StudentId
{
[DataMember]
public Guid Id { get; set; }
}
And then your global flag:
public static class SerializationFlags
{
[ThreadStatic]
static bool studentGuidOnly;
public static bool StudentGuidOnly
{
get { return studentGuidOnly; }
set { studentGuidOnly = value; }
}
}
Next you must create a IDataContractSurrogate class telling the DataContractSerializer what replacements to make. In this example you will conditionally replace Student when only the Id is desired. Since you are only doing serialization, not deserialization or schema generation, most methods can remain unimplemented:
public class StudentSurrogate : IDataContractSurrogate
{
#region IDataContractSurrogate Members
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public Type GetDataContractType(Type type)
{
if (type == typeof(Student) && SerializationFlags.StudentGuidOnly)
{
return typeof(StudentId);
}
return type;
}
public object GetDeserializedObject(object obj, Type targetType)
{
throw new NotImplementedException();
}
public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection customDataTypes)
{
throw new NotImplementedException();
}
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj != null)
{
var type = obj.GetType();
if (type == typeof(Student) && SerializationFlags.StudentGuidOnly)
{
var surrogate = new StudentId
{
Id = ((Student)obj).Id,
};
return surrogate;
}
}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
throw new NotImplementedException();
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
#endregion
}
And finally, here is an example of how it is used:
public static class DataContractSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string GetXml(T obj, DataContractSerializer serializer) where T : class
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " "; // The indentation used in the test string.
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static string GetXml(T obj) where T : class
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return GetXml(obj, serializer);
}
}
public static class SurrogateTest
{
public static void Test()
{
Student kid = new Student();
kid.Id = Guid.NewGuid();
kid.FirstName = "foo";
kid.LastName = "bar";
DataContractSerializer dcs = new DataContractSerializer(
typeof(Student),
new Type [] { typeof(StudentId) },
Int32.MaxValue,
false, true, new StudentSurrogate());
SerializationFlags.StudentGuidOnly = false;
string xml1 = DataContractSerializerHelper.GetXml(kid, dcs);
SerializationFlags.StudentGuidOnly = true;
string xml2 = DataContractSerializerHelper.GetXml(kid, dcs);
}
}
In this test case, xml1 is
foo
fa98b508-2fe9-4a09-b551-ba2ed1f70b70
bar
and xml2 is
fa98b508-2fe9-4a09-b551-ba2ed1f70b70
which is what you seek. Finally, note that, while my test case serializes Student as a top-level object, the replacement will occur if it is nested deep inside some class object graph.
For another example, see here: http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx