WCF collection serialization, IList or List? Does it matter? - wcf

Is there a preferable collections object when serializing over WCF? I'm trying to decide between List or IList, and wondering if it makes a difference?

Does not matter from serialization point of view. There is no IList or List on the wire. Both will result in the same XML.
From MSDN:
All list collections of the same type are considered to have the same
data contract (unless they are customized using the
CollectionDataContractAttribute attribute, as discussed later in this
topic).Thus, for example, the following data contracts are equivalent.
[DataContract(Name = "PurchaseOrder")]
public class PurchaseOrder1
{
[DataMember]
public string customerName;
[DataMember]
public Collection<Item> items;
[DataMember]
public string[] comments;
}
[DataContract(Name = "PurchaseOrder")]
public class PurchaseOrder2
{
[DataMember]
public string customerName;
[DataMember]
public List<Item> items;
[DataMember]
public BindingList<string> comments;
}

Related

WCF serialization issue when moving existing class properties to newly created base class

I'm seeing the serialization issue at the client side for the following scenario.
Let's say we have the following class and method in our service code
[DataContract]
public class Derived
{
[DataMember]
public string A { get; set; }
[DataMember]
public string B { get; set; }
[DataMember]
public string C { get; set; }
[DataMember]
public string D { get; set; }
}
and the service interface has the method
[OperationContract]
Derived GetDerived();
Implementation of the method -
public Derived GetDerived()
{
var d = new Derived() {A = "A", B = "B", C = "C", D = "D"};
return d;
}
For this WCF service if I create the client proxy (by adding service reference) and do the GetDerived() call, everything works fine.
Let's change the entity in service code little bit
[DataContract]
public class Base
{
[DataMember]
public string B { get; set; }
}
[DataContract]
public class Derived : Base
{
[DataMember]
public string A { get; set; }
[DataMember]
public string C { get; set; }
[DataMember]
public string D { get; set; }
}
So in this case I created a new Base class and moved property 'B' to the Base class. With the same old proxy at the client side, if I do GetDerived call, I do not see the value of A properly serialized at the client side. However, the SOAP message for previous version and the current version is the same (only order changed). I came across this http://msdn.microsoft.com/en-us/library/ms729813.aspx article explaining the ordering. Since I moved 'B' to base class, I don't see anyway to control it's order in derived class.
Is there any workaround to this problem? This breaks the backward compatibility to the client.
On the other hand, If I add the new property, let's say C1 to Derived class (or any existing class), it changes the order as well. How come this doesn't break the client? vs. the scenario that I mentioned earlier.
Using the example above, I overloaded the property "B" in the derived class and had it refer to the Base class (I'm working in VB, sorry):
#region "This shenanigans prevents breaking the contract when moving some properties to the base class.
<DataMember()> Public Overloads Property B() As String
Get
Return MyBase.B
End Get
Set(value As String)
MyBase.B = value
End Set
End Property
#End Region
This way my base class methods can still operate on B. If we ever get around to implementing wcf versioning, or have some other need to change the contract, I can strip out that overload in the derived class and everything should still just work.
-JG

How to inherit three data contracts in a single object?

How to invoke three data contract objects and create it in a single object?
I have a data contract class like this
[Serializable]
[DataContract]
public class Address
{
[DataMember]
public long AddressId { get; set; }
}
another data contract class like
[Serializable]
[DataContract]
public class Email
{
[DataMember]
public long EmailId { get; set; }
}
another data contract class like
[Serializable]
[DataContract]
public class Phone
{
[DataMember]
public long PhoneId { get; set; }
}
Now i want to use the AddressId, EmailId, PhoneId in the same method.
How it is possible??
Please, keep the [DataContract] attrubute only, you don't need decorating with Serializable as well.
Well, one have the following options with WCF Data Contracts:
Composite Data Contracts.
Member fields of any class marked as DataMember can be data contracts themselves, once they're decorated with DataContract attribute too. Aggregation of all nested data contracts illustrates the fact that data contracts are recursive in nature. WCF detects all the data contract enabled properties in the object graph and captures their state as well.
[DataContract]
class Address
{
[DataMember]
public long AddressId { get; set; }
}
// The same for the rest two, and then an aggregating type.
[DataContract]
class Contact
{
[DataMember]
public Address Address {get;set;} // here we go
[DataMember]
public Email Email {get;set;}
[DataMember]
public Phone Phone {get;set;}
}
Data Contract Hierarchy
Your data contract class may be a subclass of another data contract class, here you just have to explicitly opt-in for a given data contract, i.e. specify the DataContract on each type in the hierarchy tree.
[DataContract]
class ContactDetails
{
[DataMember]
public long AddressId { get; set; }
// you could move the phone and email details here too.
}
[DataContract]
class Contact : ContactDetails
{
[DataMember]
public string Name { get; set; }
}
You can't have three separate classes for each one and inherit from them at once in .Net. And my suggestion is the first case for you - that is data contract aggregation.
Bonus: Polymorphic Type Reference.
Applying the [KnownType(Type type)] attribute on a base type for passing polymorphic objects as operation contract arguments. This is definately not your case.
Contracts applied to classes to provide service metadata for your service (service class just can use decorated classes as parameter types in service methods). So - if you want to compose some type (class) from existing properties - this is not related to WCF contracts.

.NET WebAPI Serialization k_BackingField Nastiness

When i serialize the following:
[Serializable]
public class Error
{
public string Status { get; set; }
public string Message { get; set; }
public string ErrorReferenceCode { get; set; }
public List<FriendlyError> Errors { get; set; }
}
I get this disgusting mess:
<ErrorRootOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Printmee.Api">
<_x003C_Errors_x003E_k__BackingField>
An exception has occurred. Please contact printmee support
</_x003C_Errors_x003E_k__BackingField>
<_x003C_LookupCode_x003E_k__BackingField>988232ec-6bc9-48f3-8116-7ff7c71302dd</_x003C_LookupCode_x003E_k__BackingField>
</ErrorRootOfstring>
What gives? How can i make this pretty? JSON responses also contain the k_BackingField
By default you don't need to use neither [Serializable] nor [DataContract] to work with Web API.
Just leave your model as is, and Web API would serialize all the public properties for you.
Only if you want to have more control about what's included, you then decorate your class with [DataContract] and the properties to be included with [DataMember] (because both DCS and JSON.NET respsect these attributes).
If for some reason, you need the [Serializable] on your class (i.e. you are serializing it into a memory stream for some reason, doing deep copies etc), then you have to use both attributes in conjunction to prevent the backing field names:
[Serializable]
[DataContract]
public class Error
{
[DataMember]
public string Status { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public string ErrorReferenceCode { get; set; }
[DataMember]
public List<FriendlyError> Errors { get; set; }
}
There is a more general solution: you can configure the Json Serializer to ignore the [Serializable] attribute, so that you don't have to change the attributes in your classes.
You should make this configuration change in the application start, i.e. in Global.asax Application_Start event:
var serializerSettings =
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
var contractResolver =
(DefaultContractResolver)serializerSettings.ContractResolver;
contractResolver.IgnoreSerializableAttribute = true;
You can also make other changes to the Json serialization, like specifying formats for serializing dates, and many other things.
This will only apply to the Web API JSON serialization. The other serializations in the app (Web API XML serialization, MVC JsonResult...) won't be affected by this setting.
Try using DataContract instead of Serializable for marking your class. For more detail on why, look at this good blog post on serializing automatic properties.
The [DataContract] attributes dosn't worked for me, so it was not an option.
XmlSerializer ignores [XmlAttribute] in WebApi
The above resolution solved it for me.
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

Can I use DataContract and Serializable together?

I am working on WCF service. My all class are already serialize using [Serializable] attribute but due to "k__BackingField" Property Naming problem I used DataContract and DataMember attribute.
so Can i use both attribute together like following:
[Serializable]
[DataContract]
public class User
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int UserID { get; set; }
}
is this correct?
I also got similar solution here.
C# automatic property deserialization of JSON
Serializable and DataContract (not versus?)
I found an article on MSDN according to this we can use both attribute DataContract and Serializable together.
With [Serializable], all fields become part of the data contract (unless they are marked with [NonSerialized]). With [DataContract], only members marked with [DataMember] are included. Note that if a type has both [DataContract] and [Serializable] attributes on it, it will use the [DataContract] mapping
http://msdn.microsoft.com/en-us/magazine/cc163569.aspx
if the problem is in naming why don't you use
[XmlElement(ElementName = "Name")]
public string Name { get; set; }

WCF wrap variable complex types for REST

I'm implementing a lo-REST API and looking to return either XML or JSON. Building it in .NET WCF.
I like the design of both Flickr and Last FM APIs which wrap their variable complex types in a simple response ala:
<lfm status="ok">
<user>
<name>RJ</name>
<realname>Richard Jones </realname>
<country>UK</country>
<age>27</age>
</user>
</lfm>
or
<lfm status="ok">
<track>
<name>Best track ever</name>
<album>Thriller</album>
</user>
</lfm>
or
<lfm status="fail">
... error details
</lfm>
Serialization of the complex types is simple as you'd expect (using DataContract, DataMember etc). But wrapping it in some kind of custom response is tripping me up because of the variable complex types that may be contained inside. Giving the response a member of type object which is filled by the complex type does not serialize:
[DataContract]
public class Response
{
public enum ResponseStatus
{
ok,
fail
}
[DataMember]
public ResponseStatus Status { get; set; }
[DataMember]
public object Data { get; set; }
}
Any ideas or help is greatly appreciated.
Many thanks,
Alex
EDIT:
Tim Roberts provides an interesting solution although it doesn't serialise nicely. An option is to have all potential complex types as properties with [DataMember(EmitDefaultValue = false)] specified so nulls do not serialise. Not sure this is the best solution though.
You could define a class hierarchy for your Data types within Response:
e.g.,
[DataContract]
public abstract class Data
{ }
[DataContract]
public class FooData : Data
{ }
[DataContract]
public class BarData : Data
{ }
then indicate the known-types on the Response class:
[DataContract]
[KnownType(typeof(FooData))]
[KnownType(typeof(BarData))]
public class Response
{
public enum ResponseStatus
{
ok,
fail
}
[DataMember]
public ResponseStatus Status { get; set; }
[DataMember]
public Data Data { get; set; }
}