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

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.

Related

PetaPoco - Including Custom Partial Class Properties in WCF Response

I have been experimenting with using PetaPoco for a small project I am working, and it has been awesome so far.
I have created some additional, non auto-generated partial classes to hold various computed values, as shown in my example below. I can't get these additional properties to be serialized into a WCF response, but all of the properties in the auto-generated stuff serializes just fine. I tried using [Serializable] and [DataContract] on these custom properties, but they break the WCF service altogether.
Any ideas?
public partial class Session
{
[ResultColumn]
public int ConnectedUserCount
{
get
{
AssistedServiceDB db = new AssistedServiceDB();
return db.ExecuteScalar<int>("SELECT Count(*) FROM Session_AssistedServiceUser WHERE IsConnected = 1");
}
}
There are couple of things to look to get partial WCF DataContracts to work. First, if the other Session class is marked with the DataContract then this class would also need to be marked the same way. This is assuming the ResultSession class is also serializable and/or marked as DataContract. The other issue is WCF requires properties to, as a minimum, have private setters so the ConnectedUserCount property needs to be changed to have one.

WCF with shared objects and derived classes on client

I have a WCF service and I'm sharing types with a client in a shared assembly.
If the client create a derived class will it be possible to pass back the derived type to the service so that I can read the added properties through reflection ?
I tried but having issues with KnownTypes since the service don't know how to deserialize the derived type.
[Serializable]
public abstract class Car : ICar
{........
//on the client :
[Serializable]
public class MyCar : Car
{......
when passing myCar to Service I get the exception complaining about knownType but I cant add this on the server since I wont know what the client will be sending through and I want to handle extra properties through reflection.
Possible to register client types as knowntypes at runtime ?
Is this maybe the solution ?
http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx
This is not possible. Both service and client has to know what types will be sent in messages. If you want to use known type you have to define that relation to parent type on the service.
Why do you need to know added properties on the server?
I think there is a way.
I vaguely remember that when I studied WCF, I met ExtensionData which should be a mechanism to get everything that does not match the serialization of the class. for example, if you enable ExtensionData and you are in this situation
//Server
public class GenericRQ
{
public string GenericProperty {get;set;}
}
public Service GenericService
{
Public void GenericMethod(GenericRQ RQ)
{
}
}
// client
Public class MoreSpecificRQ : GenericRQ
{
public string SpecificProperty {get;set;}
}
At
Public void GenericMethod(GenericRQ RQ)
{
// the serializer adds automatically in RQ.ExtensionData everything that has come and that does not match the class GenericRQ.
}
On how to enable ExtensionData you to easily search on the web

Using KnowTypeAttribute in WCF Service

I have a situation where I need to pass a list of objects to my service. The objects have to be of type ELEMENT. I have my Element interface defined like so
public interface IElement{ }
Then I have my DataContracts inheriting this IElement class Like so . . . .
[KnownType(typeof(Common.IElement))]
[DataContract]
public abstract class IPet : IElement
{.....}
I also have a KnownType attribute on my Service interface like so
[ServiceContract(Name="Pets", SessionMode = SessionMode.Allowed)]
[ServiceKnownType(typeof(Memberships.PetServiceUser))]
[ServiceKnownType(typeof(.Common.IElement))]
[DeliveryRequirements(RequireOrderedDelivery=true)]
public interface IPetService {.....}
Problem is on the client side, the IElement type is not available on deserialization of service types on client. Any idea what I may be doing wrong here and how I can go about correcting this please?
None
I'm not 100 percent sure I understand everything you're trying to do here, but it seems upside-down to me. The usual way to use the KnownType attribute is to decorate the base type with the derived types. Something along the lines of:
[DataContract]
[KnownType(typeof(Pet))]
[KnownType(typeof(...
...
public class Element: IElement
{
....

WCF DataContract Upcasting

I'm trying to take a datacontract object that I received on the server, do some manipulation on it and then return an upcasted version of it however it doesn't seem to be working. I can get it to work by using the KnownType or ServiceKnownType attributes, but I don't want to roundtrip all of the data. Below is an example:
[DataContract]
public class MyBaseObject
{
[DataMember]
public int Id { get; set; }
}
[DataContract]
public class MyDerivedObject : MyBaseObject
{
[DataMember]
public string Name { get; set; }
}
[ServiceContract(Namespace = "http://My.Web.Service")]
public interface IServiceProvider
{
[OperationContract]
List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects);
}
public class ServiceProvider : IServiceProvider
{
public List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects)
{
... do some work ...
myDerivedObjects[0].Id = 123;
myDerivedObjects[1].Id = 456;
myDerivedObjects[2].Id = 789;
... do some work ...
return myDerivedObjects.Cast<MyBaseObject>().ToList();
}
}
Anybody have any ideas how to get this to work without having to recreate new objects or using the KnownType attributes?
I think that your problem is that you are trying to send over a generic list.
It will work if you encapsulate the list in an object. That is create an object with a single public property which is the generic list.
You also need to make sure that all classes that are not used directly in the contract are marked as serializable.
If you want to return the derived objects then there will always be a round trip because the client and the service are separate. In order for the client to update its own list of MyBaseObjects it has to deserialize the list of MyDerivedObjects that came from the server.
The use of KnownType and/or ServiceKnownType is needed because this leads to the addition of that type information into WSDL, which is in turn used by the client to deserialize the messages to the correct type.
For starters, a useful tool for testing the scenario you've described: http://www.wcfstorm.com
You might try creating a DataContractSurrogate (IDataContractSurrogate) and returning your base type for the call to GetDataContractType. I'm not really sure that's how it was intended to be used so you still may be better of with "the extra work", but maybe I don't understand the scope of that extra work.
One of the problems with WCF (and .net remoting) is that it they tries to make “message passing” look like method calls.
This fall down when you try to use too many “oop” type designs.
The fact that the messages are
represented by .net classes, does not
make all of their behaviour like .net
class.
See this, and this, for more on the problem of Leaking Abstraction.
So you need to start thinking about message passing not object when designing your WCF interfaces, or you will hit lots of problems like this.

Is it possible to serialize objects without a parameterless constructor in WCF?

I know that a private parameterless constructor works but what about an object with no parameterless constructors?
I would like to expose types from a third party library so I have no control over the type definitions.
If there is a way what is the easiest? E.g. I don't what to have to create a sub type.
Edit:
What I'm looking for is something like the level of customization shown here: http://msdn.microsoft.com/en-us/magazine/cc163902.aspx
although I don't want to have to resort to streams to serialize/deserialize.
You can't really make arbitrary types serializable; in some cases (XmlSerializer, for example) the runtime exposes options to spoof the attributes. But DataContractSerializer doesn't allow this. Feasible options:
hide the classes behind your own types that are serializable (lots of work)
provide binary formatter surrogates (yeuch)
write your own serialization core (a lot of work to get right)
Essentially, if something isn't designed for serialization, very little of the framework will let you serialize it.
I just ran a little test, using a WCF Service that returns an basic object that does not have a default constructor.
//[DataContract]
//[Serializable]
public class MyObject
{
public MyObject(string _name)
{
Name = _name;
}
//[DataMember]
public string Name { get; set; }
//[DataMember]
public string Address { get; set; }
}
Here is what the service looks like:
public class MyService : IMyService
{
#region IMyService Members
public MyObject GetByName(string _name)
{
return new MyObject(_name) { Address = "Test Address" };
}
#endregion
}
This actually works, as long as MyObject is either a [DataContract] or [Serializable]. Interestingly, it doesn't seem to need the default constructor on the client side. There is a related post here:
How does WCF deserialization instantiate objects without calling a constructor?
I am not a WCF expert but it is unlikely that they support serialization on a constructor with arbitrary types. Namely because what would they pass in for values? You could pass null for reference types and empty values for structs. But what good would a type be that could be constructed with completely empty data?
I think you are stuck with 1 of 2 options
Sub class the type in question and pass appropriate default values to the non-parameterless constructor
Create a type that exists soley for serialization. Once completed it can create an instance of the original type that you are interested in. It is a bridge of sorts.
Personally I would go for #2. Make the class a data only structure and optimize it for serialization and factory purposes.