Difficulties reading PSObject using WCF Message class
Issue: We would not be able to deserialize powershell object (PSObject) using WCF Message class directly.
Error:
"The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter schemas.xyz.com/Services/MyService:DoServiceResult. The InnerException message was 'Member 'CliXml' was not found.'.".
• Cause –
Failing Message:
<CliXml i:type="d3p1:string" xmlns:d3p1="www.w3.org/2001/XMLSchema"><Objs Version="1.1.0.1" xmlns="schemas.microsoft.com/powershell/2004/04">
Working Message:
<CliXml xmlns:d7p1="www.w3.org/2001/XMLSchema" i:type="d7p1:string" xmlns=""><Objs Version="1.1.0.1" xmlns="schemas.microsoft.com/powershell/2004/04">
Working message defines the namespace for the CliXml element where the failing version does not.
• Resolution –
We added a message inspector on the WCF services (not the client) and inspected the message in BeforeSendReply. It can also be compare by taking a service side WCF traces.
A simple workaround for this is to make a change similar to this:
MessageConverter.cs:
public Message ResponseToMessage(ResponseBase response)
{
try
{
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
using (var tw = new XmlTextWriter(sw))
{
var serializer = new DataContractSerializer(response.GetType(), BodyInfo.Operation + "Result", String.Empty);
serializer.WriteStartObject(tw, response);
tw.WriteAttributeString("xmlns", "b", null, OperationInfo.Service.Namespaces.Base); // "base" namespace
tw.WriteAttributeString("xmlns", "e", null, OperationInfo.Namespaces.Response ); // "entity" namespace
serializer.WriteObjectContent(tw, response);
serializer.WriteEndObject(tw);
}
var responseBody = String.Format("<{0} xmlns=\"{1}\">{2}</{0}>", BodyInfo.Operation + "Response", OperationInfo.Service.Namespaces.Service, sb.ToString());
responseBody = responseBody.Replace("<CliXml ", "<CliXml xmlns=\"\" ");
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(responseBody));
var responseAction = OperationInfo.Service.Namespaces.ReplyAction + BodyInfo.Operation + "Response";
return Message.CreateMessage(SoapMessage.Version, responseAction, new XmlNodeReader(doc));
}
catch (Exception ex)
{
throw new ApplicationException(String.Format("ResponseToMessage exception: '{0}'!", ex.Message), ex);
}
}
With this only change on the server side “ServiceHosting”, the “client” is able to read the “PSObject” information de-serialized perfectly fine.
Rohit Soni (MSFT)