wcf serialisation - wcf

Fairly new to WCF and need help with understanding why serialisation is not working correctly.
Service definition - I just want to post, serialise into a LogDeviceCommunication object and then just return the object as a simple test
[OperationContract]
[WebInvoke(UriTemplate = "AddDeviceCommunicationLog", RequestFormat =
WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, Method = "POST")]
LogDeviceCommunication AddDeviceCommunicationLog(LogDeviceCommunication
deviceCommunicationEntry);
public LogDeviceCommunication AddDeviceCommunicationLog(LogDeviceCommunication
deviceCommunicationEntry)
{
return deviceCommunicationEntry;
}
At the moment I am just posting the following XML with Fiddler as a test.
<?xml version="1.0" encoding="UTF-8"?>
<LogDeviceCommunication>
<ID>1207a26e-ab59-4977-b7eb-b2776205cffe</ID>
<DeviceID>A42E8707-7C65-45AA-8E58-5D21F53DA101</DeviceID>
<Time>2012-03-14T15:38:28.379Z</Time>
<Line>0</Line>
<Tab>0</Tab>
<Info>Starting Synchronisation</Info>
</LogDeviceCommunication>
Results returned from Fiddler
<LogDeviceCommunication z:Id="i1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<ChangeTracker z:Id="i2"
xmlns:a="http://schemas.datacontract.org/2004/07/conxEntities">
<a:ExtendedProperties/>
<a:ObjectsAddedToCollectionProperties/>
<a:ObjectsRemovedFromCollectionProperties/>
<a:OriginalValues/>
<a:State>Added</a:State>
</ChangeTracker>
<DeviceID>00000000-0000-0000-0000-000000000000</DeviceID>
<ID>1207a26e-ab59-4977-b7eb-b2776205cffe</ID>
<Info i:nil="true"/>
<Line i:nil="true"/>
<Tab i:nil="true"/>
<Time>2012-03-14T15:38:28.379Z</Time>
</LogDeviceCommunication>
Why does the DeviceID contain the 0000's (I assume it's a null Guid) while the ID contains the correct Guid; also why do the Info, Line and Info elements contain nil values?
The LogDeviceCommunication is a POCO generated from EF4 using the ADO.NET Self Tracking Template
Condensed version is
[DataContract(IsReference = true, Namespace = "")]
public partial class LogDeviceCommunication: IObjectWithChangeTracker,
INotifyPropertyChanged
[DataMember]
public System.Guid DeviceID
[DataMember]
public System.DateTime Time
[DataMember]
public Nullable<int> Line
[DataMember]
public Nullable<int> Tab
[DataMember]
public string Info
[DataMember]
public System.Guid ID
I am sure I am doing something incorrectly so any help appreciated.

The problem lies in the required ordering of the XML.
WCF Datacontract, some fields do not deserialize
http://neimke.blogspot.co.nz/2012/03/serialization-ordering-causes-problems.html

When WCF receives your request, its deserialization machinery will create a new instance of the LogDeviceCommunication type to populate with the values it receives. It seems that the code from the EF partial class of your instance is being triggered and it results in what you post in your question.
Try setting a debugger break point on the return statement in your AddDeviceCommunicationLog method to see what EF & WCF deserialized for you. If it's just as what you posted then the issue is likely caused by the EF plumbing code. Also, you may want to enable WCF message tracing to see what WCF is actually receiving and sending back.
EDIT: Just ran across this blog post that shows some of the interaction between EF & WCF. You may want to review it to see if it's applicable to your issue.

I bet the other parts of the class, generated by that template, include the elements you're seeing.
In general, it's not a good idea to return EF entities (or any complex .NET type) from a web service - they drag along implementation dependencies. Return a purely POCO class as a DTO instead.

Related

How to serialize complex model to xml format wcf

I am developing a wcf application which is taking c# request model as an input and returning complex response c# model after populating data in it from database. I am using SOAP UI client tool to test my service.
Earlier i had decorated my contract with XmlSerializerFormat attribute and after submitting request i was able to get the response in Result tab of SOAP UI tool. Below is the code snippet of it :
[ServiceContract]
[XmlSerializerFormat]
public interface IService1
{
[OperationContract]
Employee GetData(Employee value);
}
[DataContract]
public class Employee
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string Address { get; set; }
}
But now due to some reasons i have removed XmlSerializerFormat attribute from contract and i want default serializer to take care of it. But when i am submitting the request from client , my response model is populating with results but Response tab of SOAP UI shows empty response.
During Response model population when i am removing certain properties from response model, i am able to see result in response tab of SOAP UI tool.
Is Default serializer in facing some issues while serializing some of property of my model. Any other attribute apart from XmlSerializerFormat ?
Please let me know where i am lacking or is there any alternative of XmlSerializerFormat attribute.
Thnx in Advance
Try adding DataContract attribute to the Employee on the class level and DataMember attribute to its properties that you want to be serialized. If it has complex property types of its own they also may need to be decorated similarly. Default serializer in WCF is DataContract serializer FYI.

how to set attributes in soap format WCF

how to set attributes for soap message:
for example my soap messg look like following
<doPaymentResult xmlns:a="http://schemas.datacontract.org/2004/07/MemoService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:errors i:nil="true"/>
<a:messages>
<a:MessageEntity>
<a:codeField>Payment Request Successful</a:codeField>
<a:textField i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</a:MessageEntity>
</a:messages>
<a:requestTrackCode>20130430T125904R14646</a:requestTrackCode>
<a:status i:nil="true"/>
</doPaymentResult>
</doPaymentResponse>
but i need a soap message which take attributes not elements
like following
<doPaymentResult xmlns:a="http://schemas.datacontract.org/2004/07/MemoService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:errors i:nil="true"/>
<a:messages>
<a:MessageEntity codeField="Payment Request Successful">
some text here
</a:MessageEntity>
</a:messages>
<a:requestTrackCode>20130430T125904R14646</a:requestTrackCode>
<a:status i:nil="true"/>
</doPaymentResult>
</doPaymentResponse>
I am using datacontract in class.
It’s a common problem – you want to return an object from a WCF service as XML, but you either want, or need, to deliver some or all of the property values as XML Attributes instead of XML Elements; but you can’t because the DataContractSerializer doesn’t support attributes (you’re most likely to have seen this StackOverflow QA if you’ve done a web search). Most likely you’ve then migrated all your WCF service code to using the XmlSerializer (with all the XmlElement/XmlAttribute/XmlType attributes et al) – and you’ve cursed loudly.
Well, I’m here to rescue you, because it is possible – and the answer to the problem is actually inferred from the MSDN article entitled ‘Types supported by the Data Contract Serializer’.
The example I’m going to give is purely for illustration purposes only. I don’t have a lot of time, so work with me!
•Create a new Asp.Net WCF service application, you can use Cassini as your web server (probably easier – otherwise you might have to enable Asp.Net compatibility mode).
•Open the web.config and delete the element that was created for the new service.
•The interface and implementation model for this example is overkill. Move the [ServiceContract] and [OperationContract] declarations from the interface that was created for you new service to the class that was also created. Delete the interface.
•Open the .svc markup file and add the following at the end: Factory="System.ServiceModel.Activation.WebServiceHostFactory" – this enables the zero-configuration WCF model for this service (we’re going to create a RESTful service).
•Paste the following class declarations into your svc codebehind:
public interface IExampleData
{
string Description { get; set; }
string Name { get; set; }
int ID { get; set; }
}
public class ExampleData : IExampleData
{
public string Description { get; set; }
public string Name { get; set; }
public int ID { get; set; }
}
public class ExampleDataAttributed : ExampleData, IXmlSerializable
{
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
//implement if remote callers are going to pass your object in
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("id", ID.ToString());
writer.WriteAttributeString("name", Name);
//we'll keep the description as an element as it could be long.
writer.WriteElementString("description", Description);
}
#endregion
}
Just to demonstrate the point, the class that will be part-serialized to attributes simply derives from one that will be serialized as normal.
•Now add the following two methods to your service class:
[OperationContract]
[WebGet(UriTemplate = "/test1")]
public ExampleData Test1()
{
return new ExampleData() { ID = 1,
Name = "Element-centric",
Description =
"The contents of this item are entirely serialized to elements - as normal" };
}
[OperationContract]
[WebGet(UriTemplate = "/test2")]
public ExampleDataAttributed Test2()
{
return new ExampleData_Attributed() { ID = 2,
Name = "Mixed",
Description =
"Everything except this description will be serialized to attributes" };
}
Cover, and bake for 40 minutes (that is – Build it).
If you left your service as Service1.svc, then run it and open up IE and browse to http://localhost:[port of cassini]/test1
The result should look something like this:
<JSLabs.ExampleData
xmlns="http://schemas.datacontract.org/2004/07/ExampleNamespace"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Description>
The contents of this item are entirely serialized to elements - as normal
</Description>
<ID>
1
</ID>
<Name>
Element-centric
</Name>
</JSLabs.ExampleData>
Now browse to http://localhost:[port of cassini]/test2
<JSLabs.ExampleDataAttributed id="2" name="Mixed"
xmlns="http://schemas.datacontract.org/2004/07/JobServe.Labs.Web">
<description>Everything except this description will be
serialized to attributes</description>
</JSLabs.ExampleDataAttributed>
It’s made a little less impressive by that nasty ‘orrible “xmlns=” attribute that the WCF data contract serializer automatically puts on the type – but, as you can see, the ‘ID’ and ‘Name’ properties have indeed been pushed out as attributes!
We could have made both methods return IExampleData and then used the KnownType attribute on that interface in order to get it to support either (according to what the code of the methods returned).
To support deserializing an object from the attributes, all you have to do is to implement the IXmlSerializable.ReadXml method.
Finally, as the aforementioned MSDN article says about the supported types – you should also be able to use XmlElement/XmlNode types as a way of representing XML directly – the DataContractSerializer, like in this case, take the short route and simply gets the Xml.
This also shouldn’t affect JSON formatting if you’re dual-outputting objects for either XML or JSON clients.
Check the source of this article

WCF and Castle library (Glass Mapper)

hello I have WCF service with webHttpEndpointBehavior under Sitecore 6 and I use Glass Mapper to read items, Glass mapper has depends on Castle library.
It is working well, but i have some methods with Contract like:
[OperationContract]
[WebInvoke(Method = "POST",BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
List<Shade> GetAllShades(int columns, int rows);
where I try return list of my class in JSON format,
during debug my service with SvcTraceViewer.exe I find out next error:
There was an error while trying to serialize parameter
:GetFamilyShadesResult. The InnerException message was 'Type
'Castle.Proxies.ShadeProxy' with data contract name
'ShadeProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies' 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.
How to resole this issue? Castle.Proxies.ShadeProxy is a dynamic class under Castle and I can't use KnownTypeAttribute.
Actually if I JSON.net library and return results as string everything works fine.
I assume you have a class that links to other classes loaded via Glass, e.g.
[SitecoreClass]
public class Shade{
[SitecoreField]
public virtual IEnumerable<AnotherClass> SomeField{get;set;}
[SitecoreChildren]
public virtual IEnumerable<AnotherClass> Children{get;set;}
}
[SitecoreClass]
public class AnotherClass{}
To allow lazy loading of classes Glass uses proxies generated by Castle, so at runtime when the classes are loaded into the SomeField property you actually get a sub-class of the AnotherClass class.
To resolve this you have to explicitly tell class to load the other classes as concrete types, updating the SitecoreField attribute should fix this problem:
[SitecoreClass]
public class Shade{
[SitecoreField(Setting=SitecoreFieldSettings.DontLazyLoad)]
public virtual IEnumerable<AnotherClass> SomeField{get;set;}
[SitecoreChildren(IsLazy=false)]
public virtual IEnumerable<AnotherClass> Children{get;set;}
}
[SitecoreClass]
public class AnotherClass{}

WCF and interfaces

I need to have 2 families of classes (one on server and one on client side) which are identical in data structure but differs in behavior. Also I suppose that these fmailies will be enough big, thus I don't want to implement intermediate level of DTO and transformations into and from it.
I decided to move in following manner: declare shared assembly with declaration of data and services interfaces like these ones:
public interface ITest
{
string Title { get; set; }
int Value { get; set; }
}
public interface IService
{
ITest GetData();
}
Having these declarations I can implement these interfaces on server side for example basing on Entity Framework (data) and WCF (services). On the client side I can use for example Dependency Properties (data) and WCF (service).
When I started trying to implement this, I met several troubes.
First one was about server side of WCF - it simply do not want to work with interfaces as return parameters. Thanks to StackOverflow this issue was resolved like here
.
Next problem is that XML rendered by server side includes qulified assembly name of serialized on the server class.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetDataResponse xmlns="http://tempuri.org/">
<Test z:Id="1" z:Type="Dist.Server.Model.Test" z:Assembly="Dist.Server, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://schemas.datacontract.org/2004/07/Dist.Server.Model" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Title z:Id="2">Test</Title>
<Value>123</Value>
</Test>
</GetDataResponse>
</s:Body>
</s:Envelope>
Thus during deserialization on client side there was an attempt to load this type. As this type is inaccessible on client side, I had to implement some kind of type mapping. I found that this is quite easy as NetDataContractSerializer used for serialization supports Binder property. Thus I override this property on client side and return correct value (hardcode in meantime, but it's OK for tests).
public class NetBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName) {
var type = Type.GetType("Client.Test, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
return type;
}
}
Now I have following picture:
- Server uses NetDataContractSerializer to serialize response. It uses actual value (calss) during serialization instead of type used in declaration of service (interface).
- Client side receives XML and starts deserialization. To resolve type, NetDataContractSerializer calls my Binder that returns correct type.
- NetDataContractSerializer creates instance of correct type and starts loading of its properties.
And here I got a trouble that I don't know how to resolve. Values of properties are not deserialized. It means that instance of class is created correctly (uninitialized instance created through reflection services), but all properties are in their default values (0 or null).
I tried to play with declaration of class on client side: mark it as [Serializable], implement ISerializable, etc., but nohing is helpful. NetDataContractSerializer requires class to be marked as [DataContract] or [Serializable]. First option leaves properties empty, second one causes exceptions like "</Test> is unexpected, expected is bla-bla-bla_Value_Ending_bla-bla-bla".
Does anybody have any suggestions on how to resolve this last step?
I can provide full sources for better understanding, but I don't know ifI can attach them here...
Thanks in advance.
You could have a look at frameworks like AutoMapper that would take care the transformation to and from DTO. This would make your life much easier.
Instead of using an interface why not create a base class containing only the data and inherit it on both sides by sharing the assembly containing this class. Playing around with the ServiceKnownType should help you fix the last issues.
You may also share the same base classes on both sides and implement the specific logic as extension methods.
Seems that problem was solved enough easily. I created own serializer and used it instead of NetDataContractSerializer. Code is quite simple:
public class MySerializer: XmlObjectSerializer
{
public override void WriteStartObject(XmlDictionaryWriter writer, object graph) {
}
public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) {
var formatter = new XmlSerializer(graph.GetType());
formatter.Serialize(writer, graph);
}
public override void WriteEndObject(XmlDictionaryWriter writer) {
}
public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) {
var realType = Type.GetType("Client.Test, Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); //temporary solution
var formatter = new XmlSerializer(realType);
return formatter.Deserialize(reader);
}
public override bool IsStartObject(XmlDictionaryReader reader) {
return true;//temporary solution
}
}
I checked SOAP that goes from server to client and it's almost the same as NetDataSerializer renders. The only difference is in attribute xmlns="".
Kai, Johann thanksfor your tries.

Do WCF and DataContractSerializer serialize CollectionDataContract-decorated collection types differently?

I have a really simple customized collection type that inherits from List<> and uses a CollectionDataContract.
When I use DataContractSerializer.WriteObject to serialize it, it respects the CollectionDataContract attribute the way I'd expect; however, when I use it as a return type for a WCF method, I get the default ArrayOfFoo.
I'm wondering if there is some decoration I'm missing in the service contract.
Details:
[DataContract(Namespace = "")]
public class Foo
{
[DataMember]
public string BarString { get; set; }
}
[CollectionDataContract(Namespace = "")]
[Serializable]
public class FooList : List<Foo> {}
If I just instantiate a Foo and then use DataContractSerializer.WriteObject to serialize it, I get what you'd expect:
<FooList>
<Foo>
<BarString>myString1</BarString>
</Foo>
</FooList>
However, if I have a service with a method like this...
[ServiceContract Name = "MyService"]
public interface IMyService
{
[OperationContract, WebGet(UriTemplate = "foos/")]
FooList GetAllFoos();
}
and then do a GET for http://www.someEndpoint.com/foos/, I get this:
<ArrayOfFoo>
<Foo>
<BarString>myString1</BarString>
</Foo>
</ArrayOfFoo>
I've also tried specifying Name="MyFooListName" in the CollectionDataContract attribute. Same results: DataContractSerializer gets the memo; WCF doesn't.
Saeed sent me in the right direction: I inadvertently ended up with XmlSerializer, when I had been hoping for DataContractSerializer.
I had ended up with XmlSerializer... well... by asking for it.
In particular, I had decorated methods in my service with the XmlSerializerFormat like this:
[ServiceContract Name = "MyService"]
public interface IMyService
{
// ... other stuff ...
[OperationContract, WebInvoke(UriTemplate = "foos/", Method = "POST")]
[XmlSerializerFormat]
Foo PostAFoo(Foo yourNewFoo);
}
I had done this in the hopes of forgiving member order in hand-rolled Foo XML blobs. Of course, when one does this one ends up with XmlSerializer, not DataContractSerializer.
When I take away the XmlSerializerFormat attribute, problem solved: WCF is now serializing my FooList collection the way I want.
See MSDN for detail:
The DataContractSerializer does not
support the programming model used by
the XmlSerializer and ASP.NET Web
services. In particular, it does not
support attributes like
XmlElementAttribute and
XmlAttributeAttribute. To enable
support for this programming model,
WCF must be switched to use the
XmlSerializer instead of the
DataContractSerializer.
So the serialization going to be done by XMLSerializer, and you can't change it.
Have you selected Generic types while configuring your WCF service? if not then,
right click and go to configuration, then select Generic Type, by default it is arraylist type.