WCF Serialization Error Using NetTCP - wcf

Using VS2012 and NetTcpBinding. I am getting the following error when I call the serviceContract from the client - The service is hosted in IIS:
There was an error while trying to serialize parameter CS.ServiceContracts.Zzzzzz.Common:GetZipCodesResult. The InnerException message was 'Type 'System.DelegateSerializationHolder+DelegateEntry' with data contract name 'DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
Here is my ServiceContract:
[ServiceContract(SessionMode = SessionMode.Allowed, Namespace = "CS.ServiceContracts.Zzzzzz.Common",
Name = "IZzzzzzCommonService")]
public interface IZzzzzzCommonService
{
[OperationContract]
GetZipCodesResponse GetZipCodes(GetZipCodesRequest request);
}
Here is my DataContract:
[DataContract]
[Serializable]
public class GetZipCodesResponse : ResponseBase
{
[DataMember(IsRequired = true)]
public List<ZipCodes> ZipCodes { get; set; }
}
And here is the ResponseBase:
[DataContract]
[Serializable]
[KnownType(typeof(GetZipCodesResponse)), XmlInclude(typeof(GetZipCodesResponse))]
public class ResponseBase
{
[DataMember(IsRequired = true)]
public int ResponseCode { get; set; }
[DataMember(IsRequired = false)]
public int ReasonCode { get; set; }
[DataMember(IsRequired = false)]
public string ReasonText { get; set; }
}
Here is the Implementation of the serviceContract Interface:
public class ZzzzzzCommonService : IZzzzzzCommonService
{
public GetZipCodesResponse GetZipCodes(GetZipCodesRequest request)
{
var response = new GetZipCodesResponse();
try
{
response.ZipCodes = ZipCodes.GetCustom(request.ZipCode, request.City, request.State);
}
catch (Exception ex)
{
this.BuildExceptionResponse(response, ex);
}
return response; // I get to this line ok, but here is where the error occurs
}
}
And here is the client code where I am calling the Service:
public void ZipCodes()
{
var endPoint = new EndpointAddress(
"net.tcp://localhost/CS.WebService.Zzzzzz.Common/ZzzzzzCommonService.svc");
var binding = new NetTcpBinding { TransferMode = TransferMode.Buffered, SendTimeout = TimeSpan.MaxValue, ReceiveTimeout = TimeSpan.MaxValue, MaxReceivedMessageSize = 100000000, MaxBufferSize = 100000000 };
using (var channel = new ChannelFactory<IZzzzzzCommonService>(binding, endPoint))
{
try
{
channel.Endpoint.Contract.SessionMode = SessionMode.Allowed;
var proxy = channel.CreateChannel();
var request = new GetZipCodesRequest();
request = new GetZipCodesRequest { ZipCode = "32701" };
response = proxy.GetZipCodes(request);
}
}
}
I have debugged the code and I am getting into the entity and the dataSet is populated with the appropriate rows but when it sends the dataset back is when I get the errors.
Not sure what I am missing. I believe I have the serviceContract and dataContract members decorated correctly so not sure why it is having problems serializing the List.

The problem was the ZipCode class. It was an Entity class and it was not able to be serialized. So I deconstructed the class and it was able to send it back to the client.

Related

Why can't I deserialize my object if the xml it contains gets slightly larger?

I am having an issue trying to send a message to the Azure service bus using the REST API and have it received using the .NET azure service bus client API classes. I can happily send and receive messages using these objects using the SDK alone, but get problems when trying to use the REST api.
I have narrowed the issue down to this minimal repro I think. Basically if I serialize my object with a small amoutn of XML as the payload thee everything works ok. If I add slightly more XML then I get an exception deserializing it. this should cut&paste into a new console application to allow repro of the issue:
using System.IO;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Xml;
using System.Xml.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
GetMessageBytes(Guid.NewGuid());
}
private static byte[] GetMessageBytes(Guid requestId)
{
var payload = XElement.Parse(#"
<blah Type='TransactionRequest' Version='1' xmlns=''>
<SomeData Type='Request' Selection='All'></SomeData>
</blah>");
var invalidPayload = XElement.Parse(#"
<blah Type='TransactionRequest' Version='1' xmlns=''>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
<SomeData Type='Request' Selection='All'></SomeData>
</blah>");
Message<XElement> message = new Message<XElement>()
{
Label = "Label",
RequestId = requestId,
Payload = payload
};
var messageBytes = EncodeMessage(message);
var expectedResponse = DecodeMessage<Message<XElement>>(messageBytes);
message = new Message<XElement>()
{
Label = "Label",
RequestId = requestId,
Payload = invalidPayload
};
messageBytes = EncodeMessage(message);
expectedResponse = DecodeMessage<Message<XElement>>(messageBytes);
Console.WriteLine(expectedResponse);
return messageBytes;
}
private static byte[] EncodeMessage<T>(T message)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
var memoryStream = new MemoryStream();
XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memoryStream);
serializer.WriteObject(binaryDictionaryWriter, message);
binaryDictionaryWriter.Flush();
var bytesToPost = memoryStream.GetBuffer();
return bytesToPost;
}
private static T DecodeMessage<T>(byte[] response)
{
var ms = new MemoryStream(response);
var serializer = new DataContractSerializer(typeof(T));
XmlDictionaryReader binaryDictionaryReader = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max);
var message = serializer.ReadObject(binaryDictionaryReader);
return (T)message;
}
}
[MessageContract(WrapperName = "Message", WrapperNamespace = "http://blah.co.uk/contracts", IsWrapped = true)]
public sealed class Message<T> where T : class
{
[MessageHeader(Namespace = "http://blah.co.uk/contracts", Name = "RequestId")]
public Guid RequestId { get; set; }
[MessageHeader(Namespace = "http://blah.co.uk/contracts", Name = "Label")]
public string Label { get; set; }
[MessageBodyMember(Namespace = "http://blah.co.uk/contracts", Name = "Payload")]
public T Payload { get; set; }
[MessageBodyMember(Namespace = "http://blah.co.uk/contracts", Name = "MonitoringResults")]
public MessageTimestamp MessageTimestamp { get; set; }
}
[DataContract]
public class MessageTimestamp
{
private ICollection<Timestamp> timestamps = new List<Timestamp>();
[DataMember]
public ICollection<Timestamp> GetAllTimestamps
{
get
{
return timestamps.ToList();
}
private set
{
timestamps = new List<Timestamp>(value);
}
}
}
public class Timestamp
{
public Operation Operation { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan TimeTaken
{
get
{
return EndTime - StartTime;
}
}
}
public enum Operation
{
OverallProcessing
}
The error that is thrown is:
There was an error deserializing the object of type
SerialisationIssue.Message1[[System.Xml.Linq.XElement, System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]`.
The input source is not correctly formatted.
I have tried serialising large amounts of just XML (ie no Message<XElement> wrapper) and that works ok, so I'm sure its not actually related to the size of the XML, but that consistently make it break.
I've reflected the actual class that is used in the ServiceBus SDK client libraries and tried to use the deserialiser found in there (DataContractBinarySerializer) but that has made no difference and seems to basically do the same thing that I'm doing manually anyway.
Any ideas on how I can find what the actual problem is? And how I might go about fixing it?
So the issue is indeed related to some apparent bug in the XmlBinaryReader as outlined in this connect issue
which can be worked around by writing some whitespace at the end of the serialized data, as suggested in this post

Return Entity Framework objects over WCF

We have a problem concerning Entity Framework objects and sending them through WCF.
We have a database, and Entity Framework created classes from that database, a 'Wallet' class in this particular situation.
We try to transfer a Wallet using this code:
public Wallet getWallet()
{
Wallet w = new Wallet();
w.name = "myname";
w.walletID = 123;
return w;
}
We need to transfer that Wallet class, but it won't work, we always encounter the same exception:
"An error occurred while receiving the HTTP response to localhost:8860/ComplementaryCoins.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details."
We searched on the internet, and there is a possibility that the error is due to the need of serialization of Entity Framework-objects.
We have absolutely no idea if this could be the case, and if this is the case, how to solve it.
Our DataContract looks like this (very simple):
[DataContract]
public partial class Wallet
{
[DataMember]
public int getwalletID { get { return walletID; } }
[DataMember]
public string getname { get { return name; } }
}
Does anyone ever encountered this problem?
EDIT: Our Entity Framework created class looks like this:
namespace ComplementaryCoins
{
using System;
using System.Collections.Generic;
public partial class Wallet
{
public Wallet()
{
this.Transaction = new HashSet<Transaction>();
this.Transaction1 = new HashSet<Transaction>();
this.User_Wallet = new HashSet<User_Wallet>();
this.Wallet_Item = new HashSet<Wallet_Item>();
}
public int walletID { get; set; }
public string name { get; set; }
public virtual ICollection<Transaction> Transaction { get; set; }
public virtual ICollection<Transaction> Transaction1 { get; set; }
public virtual ICollection<User_Wallet> User_Wallet { get; set; }
public virtual ICollection<Wallet_Item> Wallet_Item { get; set; }
}
}
Thanks for helping us.
I had the same problem some time ago and the solution for this was:
The entity framework was returning a serialized class instead of normal class.
eg. Wallet_asfawfklnaewfklawlfkawlfjlwfejlkef instead of Wallet
To solve that you can add this code:
base.Configuration.ProxyCreationEnabled = false;
in your Context file.
Since the context file is auto generated you can add it in the Context.tt
In the Context.tt file it can be added around lines 55-65:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
public <#=code.Escape(container)#>()
: base("name=<#=container.Name#>")
{
base.Configuration.ProxyCreationEnabled = false;
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
this.Configuration.LazyLoadingEnabled = false;
<#
Try specifying a setter for the properties, something like this :
[DataContract]
public partial class Wallet
{
[DataMember]
public int getwalletID { get { return walletID; } set { } }
[DataMember]
public string getname { get { return name; } set { } }
}
If it still doesn't work, you may consider creating an intermediate POCO class for this purpose, and use mapper library like AutoMapper or ValueInjecter to transfer the data from the EF objects.
The POCO class should have same properties as your EF class :
[DataContract]
public class WalletDTO
{
[DataMember]
public int walletID { get; set; }
[DataMember]
public string name { get; set; }
}
And modify your method to return this class instead :
public WalletDTO getWallet()
{
Wallet w = new Wallet(); // or get it from db using EF
var dto = new WalletDTO();
//assuming we are using ValueInjecter, this code below will transfer all matched properties from w to dto
dto.InjectFrom(w);
return dto;
}
Are you trying to recieve a IEnumerable<Wallets>? If - yes, please modify your server class that returns the IEnumerable by adding .ToArray() method

Sending complex type as a parameter in SOAP message

I have a WCF Service like following:
public class Service1 : IService1
{
public string GetData(Person person)
{
if (person != null)
{
return "OK";
}
return "Not OK!";
}
Here is my Person class:
[DataContract]
public class Person
{
[DataMember]
public int Age { get; set; }
[DataMember]
public string Name { get; set; }
}
And I'm calling service like that:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
IChannelFactory<IRequestChannel> factory = binding.BuildChannelFactory<IRequestChannel>(new BindingParameterCollection());
factory.Open();
EndpointAddress address = new EndpointAddress(url);
IRequestChannel irc = factory.CreateChannel(address);
using (irc as IDisposable)
{
irc.Open();
string soapMessage = "<GetData><person><Age>24</Age><Name>John</Name></person></GetData>";
XmlReader reader = XmlReader.Create(new StringReader(soapMessage));
Message m = Message.CreateMessage(MessageVersion.Soap11,"http://tempuri.org/IService1/GetData", reader);
Message ret = irc.Request(m);
reader.Close();
return ret.ToString();
}
When I try to send complex type like Person as a parameter to GetData method, person object is coming null. But I have no problem when I send known type like integer, string etc. as a parameter.
How can I manage to send complex type as a parameter to the service method?
I ran into a similar situation, and we ended up changing the interface of the service to be the equivalent of:
public string GetData(string person)
And we did our own object serialization before calling the web service. Immediately within the web service method we would deserialize it, and proceed as normal.

WCF xmlSerializer and Data Contract Attributes

I used XSD2Code to generate C# code from given XSD. This tool generated code snipped as below:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Orders
{
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public int OrderID {get;set;}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public string Description {get;set;}
}
Coud some one please guide me with following queires, please
If I leave the above code as it is, does WCF serializes the above class?
Currently I'm getting this error on wcf test client: ""this Operation is not
supported in WCF Test Client".
Do I need to add DataContract and DataMember on top of the above generated codes?
Which option is beter between DataContract Serializer vs XML Serializer
Thanks you.
It should work, as long as the contract (either the service contract interface or the operation contract method which uses this type) is marked with the [XmlSerializerFormat] attribute
No - if you decorate the contract with [XmlSerializerFormat], the DataContract/DataMember attributes are ignored (the XML serialization attributes, like the ones in this type, are used instead)
The XmlSerializer allows you to completely control the XML in which the types are serialized; the DataContractSerializer (DCS) doesn't (it's more limited). But the DCS has a better performance, so which one is better really depends on your scenario.
The code below shows a service which uses this type, and it works fine, even with the WcfTestClient.
public class StackOverflow_7155154
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Orders
{
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public int OrderID { get; set; }
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public string Description { get; set; }
}
[ServiceContract]
[XmlSerializerFormat]
public interface ITest
{
[OperationContract]
Orders GetOrders();
}
public class Service : ITest
{
public Orders GetOrders()
{
return new Orders { Description = "My order", OrderID = 1 };
}
}
public static void Test()
{
//MemoryStream ms = new MemoryStream();
//XmlSerializer xs = new XmlSerializer(typeof(Orders));
//Orders o = new Orders { OrderID = 1, Description = "My order" };
//xs.Serialize(ms, o);
//Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.GetOrders());
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Client WCF DataContract has empty/null values from service

I have a simple WCF service that returns the time from the server. I've confirmed that data is being sent by checking with Fiddler. Here's the result object xml that my service sends.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetTimeResponse xmlns="http://tempuri.org/">
<GetTimeResult xmlns:a="http://schemas.datacontract.org/2004/07/TestService.DataObjects" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:theTime>2010-03-26T09:14:38.066372-06:00</a:theTime>
</GetTimeResult>
</GetTimeResponse>
</s:Body>
</s:Envelope>
So, as far as I can tell, there's nothing wrong on the server end. It's receiving requests and returning results.
But on my silverlight client, all the members of the returned object are either null, blank or a default vaule. As you can see the server returns the current date and time. But in silverlight, theTime property on my object is set to 1/1/0001 12:00 AM (default value).
Sooo methinks that the DataContracts do not match up between the server and the silverlight client. Here's the DataContract for the server
[DataContract]
public class Time
{
[DataMember]
public DateTime theTime { get; set; }
}
Incredibly simple. And here's the datacontract on my silverlight client.
[DataContract]
public class Time
{
[DataMember]
public DateTime theTime { get; set; }
}
Literally the only difference is the namespaces within the application. But still the values being returned are null, empty or a .NET default.
Thanks for you help!
UPDATE
Here is the ClientBase that all my services run through. I read an excellent article here to construct it.
public class ClientBase<T> where T :class
{
private T Channel { get; set; }
private Type ContractType { get; set; }
private ClientBase()
{
ContractType = typeof( T );
}
public ClientBase(string endPointConfiguration) :this()
{
Channel = new ChannelFactory<T>( endPointConfiguration ).CreateChannel();
}
public ClientBase( EndpointAddress address, Binding binding ):this()
{
Channel = new ChannelFactory<T>( binding, address ).CreateChannel();
}
public void Begin(string methodName, object state, params object[] parameterArray)
{
Begin( methodName, null, state, parameterArray );
}
public void Begin(string methodName, EventHandler<ClientEventArgs> callBack, object state, params object[] parameterArray)
{
if(parameterArray != null)
{
Array.Resize(ref parameterArray, parameterArray.Length + 2);
}
else
{
parameterArray = new object[2];
}
parameterArray[ parameterArray.Length - 1 ] = new ObjectClientState {CallBack = callBack, MethodName = methodName, UserState = state};
parameterArray[ parameterArray.Length - 2 ] = new AsyncCallback( OnCallBack );
ContractType.InvokeMember( "Begin" + methodName,
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod |
System.Reflection.BindingFlags.Public, null, Channel, parameterArray );
}
private void OnCallBack(IAsyncResult result)
{
ObjectClientState state = result.AsyncState as ObjectClientState;
if(state == null)
return;
Object obj = ContractType.InvokeMember( "End" + state.MethodName,
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod |
System.Reflection.BindingFlags.Public, null, Channel, new object[] {result} );
if(state.CallBack != null)
{
state.CallBack( this, new ClientEventArgs {Object = obj, UserState = state.UserState} );
}
}
public class ClientEventArgs : EventArgs
{
public object Object { get; set; }
public object UserState { get; set; }
public T LoadResult<T>()
{
if( Object is T )
return ( T ) Object;
return default( T );
}
}
private class ObjectClientState
{
public EventHandler<ClientEventArgs> CallBack { get; set; }
public string MethodName { get; set; }
public object UserState { get; set; }
}
}
Here is my interface
[ServiceContract]
public interface ITestService
{
[OperationContract( AsyncPattern = true )]
IAsyncResult BeginGetTime( AsyncCallback callback, object state );
Time EndGetTime( IAsyncResult result );
}
Now I have my service class that makes calls through my BaseService class using this interface.
public class TestSiteService : ClientBase<ITestService>
{
public TestSiteService (string endPointConfiguration):base(endPointConfiguration) { }
public TestSiteService ( EndpointAddress address, Binding binding ) : base( address, binding ) { }
public void GetTime( EventHandler<ClientEventArgs> callBack )
{
Begin( "GetTime", callBack, null, null );
}
}
Finally here is the code that actually calls everything and does the work.
TestSiteService client = new TestSiteService ( new EndpointAddress( "http://localhost:3483/wcf/Service.svc" ), new BasicHttpBinding() );
client.GetTime( delegate( object res, ClientBase<ITestService>.ClientEventArgs e )
{
Dispatcher.BeginInvoke( () => lblDisplay.Text = "Welcome " + e.LoadResult<Time>().theTime );
} );
Whew....I hope no one is lost from all this code I posted :P
Because you don't set the Namespace property on your DataContractAttribute, the namespace will be sythesized from the .NET class/namespace. You can see this in the SOAP message example you posted:
http://schemas.datacontract.org/2004/07/TestService.DataObjects
In order to have the contracts be considered equal, you must set the Namespace property on the DataContract to the same value on both sides. That might look a little something like this:
[DataContract(Namespace="urn:my-test-namespace")]
Extending on Drew Marsh's correct answer (+1 - thx) I had a generated Service Reference which was working, but when I tried to use the Wcf Client Factory one implementing the correct interface (but the namespace was different) then I was experiencing the problem described.
I had no easy way to work out what the "correct" namespace should have been but simply copying the following attributes from the service reference's DataContract entity to the one in the Wcf Client Factory implementation solved the issue;
[System.Runtime.Serialization.DataContractAttribute(Name = "BOSPrice", Namespace = "http://schemas.datacontract.org/2004/07/BOSDataService")]
[System.SerializableAttribute()]