One way to achieve this is to intercept the XML response and change the root element name to something unique before it is deserialized. This can be done pretty easily with a custom IClientMessageFormatter and an associated attribute on the operation.
I just wrote this up, so "wet paint" and all, but here is what that looks like:
/// <summary>
/// An operation attribute that changes the XML root name in responses
/// </summary>
/// <example>
///
/// [ServiceContract]
/// [XmlSerializerFormat]
/// public interface IRedBlueServiceApi
/// {
/// [OperationContract]
/// [WebGet(...)]
/// [XmlChangeRoot("RedResponse")]
/// RedResponse GetRed();
///
/// [OperationContract]
/// [WebGet(...)]
/// [XmlChangeRoot("BlueResponse")]
/// BlueResponse GetBlue();
/// }
///
/// [XmlRoot("RedResponse")]
/// public class RedResponse
/// {...}
///
/// [XmlRoot("BlueResponse")]
/// public class BlueResponse
/// {...}
/// </example>
[DefaultProperty("NewRootElementName")]
public class XmlChangeRootAttribute : Attribute, IOperationBehavior
{
public XmlChangeRootAttribute(string newRootElementName)
{
NewRootElementName = newRootElementName;
}
public string NewRootElementName { get; set; }
#region IOperationBehavior Members
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
// Inject our xml root changer into the client request/response pipeline
clientOperation.Formatter = new XmlRootChangeFormatter(clientOperation.Formatter, NewRootElementName);
}
#endregion
#region Unrelated Overrides
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
}
public void AddBindingParameters(OperationDescription operationDescription,
BindingParameterCollection bindingParameters)
{
}
public void Validate(OperationDescription operationDescription)
{
}
#endregion
}
/// <summary>
/// A simple wrapper around an existing IClientMessageFormatter
/// that alters the XML root name before passing it along
/// </summary>
public class XmlRootChangeFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter _innerFormatter;
private readonly string _newRootElementName;
public XmlRootChangeFormatter(IClientMessageFormatter innerFormatter, string newRootElementName)
{
if (innerFormatter == null)
throw new ArgumentNullException("innerFormatter");
if (String.IsNullOrEmpty(newRootElementName))
throw new ArgumentException("newRootElementName is null or empty");
_innerFormatter = innerFormatter;
_newRootElementName = newRootElementName;
}
#region IClientMessageFormatter Members
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
return _innerFormatter.SerializeRequest(messageVersion, parameters);
}
public object DeserializeReply(Message message, object[] parameters)
{
if (!message.IsEmpty)
{
var doc = XDocument.Load(message.GetReaderAtBodyContents());
if (doc.Root == null)
throw new SerializationException("Could not find root in WCF messasge " + message);
// Change the root element name
doc.Root.Name = _newRootElementName;
// Create a new 'duplicate' message with the modified XML
var modifiedReply = Message.CreateMessage(message.Version, null, doc.CreateReader());
modifiedReply.Headers.CopyHeadersFrom(message.Headers);
modifiedReply.Properties.CopyProperties(message.Properties);
message = modifiedReply;
}
return _innerFormatter.DeserializeReply(message, parameters);
}
#endregion
}