WCF result deserializing to default values for value types in a list of key/value pairs - wcf

I have a WCF service and the result is a custom TimeSeries class defined as:
[DataContract]
public class TimeSeries
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<KeyValuePair<DateTime, double>> Data { get; set; }
}
My service method creates an array of these objects to return. Debugging the service method, I can see that an array containing one of these objects is created correctly (it has a name and 37 vk pairs of data). Using Fiddler, I can see that the object is being serialized and sent (the data is still correct in the HTTP response). However the problem comes when on the client I check the result object and it is incorrect. Specifically, I get a TimeSeries object with the correct name, and the correct number of of kv pairs, but they contain the default values for each DateTime and double (ie 01/01/0001 12:00AM & 0.0).
My client is Silverlight v4 and I am using an automagically generated service reference. The problem appears to be related to deserialization. Anyone have any thoughts as to why it is doing this, what I am missing, or how I can fix it?

As it is stated in Serializing a list of Key/Value pairs to XML:
KeyValuePair is not serializable, because it has read-only properties
So you need your own class, just like the answer on that page says.

An alternative rather than using your own class is to use a Dictionary<DateTime,double> instead which seems to serialize and deserialize fine.

Related

CustomConverter to compare to a property on the same class in web api

I've been writing a few customconverters, extending Newtonsofts JsonConverter and stumbled on a little problem. Say I have two properties on a class, but they cannot be the same value. Is it possible to find the value of another property in a converter... for example, say I have a model like so.
I'd want to be able to check the value of Surname in CustomCompareConverter to ensure its not the same value as Firstname
public class Person
{
[JsonConverter(typeof(CustomCompareConverter), "Surname")]
public string Firstname { get; set; }
public string Surname { get; set; }
}
```
You are trying to do multiple things with the json deserialization process that really should be separated
converting some external json into your domain object
validating the domain object.
The fact that the Surname cannot match the FirstName property is a business rule of your domain. So keep that within your domain. You can:
write a separate validator class that will check the state of your
person object and return a list of validation failures
implement IValidatableObject on your Person class and implement the
interface
write a custom validator like in this SO question
Use the JSON deserialization process as an anti-corruption layer to keep the details of external systems out of your your domain structure. Once you've take the extenal object and converted it to your domain object then use conventional means to validate that your domain object.

Why is there extra schema information on DataMember properties of base class when using WCF?

I have some DataContracts defined, one is inherited from the other. These are not the exact classes but there are something like this:
[DataContract]
public class BaseModel
{
[DataMember]
public String Id {get;set;}
}
[DataContract]
public class MyModel : BaseModel
{
[DataMember]
public String Name {get;set;}
}
I am using WCF with the basicHTTPbinding to move data from server to client. When I use fiddler to look at the data being sent it is doing something a bit strange.
In the raw data being returned, when I examine the Name property I can see 'Name' followed by the data. For the Id property I see 'Id http://schema.datacontract.org/2004/07/MyService' followed by the data. I only every see the schema.datacontract.org part for the fields from the base class. Why do only the inherited fields get that schema part? Both classes are in the same namespace. I don't want it on ANY properties as its adding significant size to my response. Is there anyway I can turn it off?
I changed each [DataContract] to include Namespace with the same value, e.g.
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MyCode.Service")]
and this has fixed my issue. Not sure why it needed to be specified since they were in the same namespace already but it does work.

Datacontract and dynamic return type WCF

I have a ServiceContract which returns dynamic type and looks like following:
public dynamic LoginViaOpenId(string openIdUrl)
The dynamic return type could be a DataContract that I have defined, or a string. But since I have not used my DataContract on the service, client does not know anything about it and cannot access it.
My DataContract is something like below:
[DataContract]
public enum OpenIdStatus
{
[EnumMember]
Authenticated,
[EnumMember]
Authenticating,
[EnumMember]
Cancelled,
[EnumMember]
Failed,
[EnumMember]
RedirectToLogon
}
I know if I had hierarchical types I could have used KnownType to conquer this, but am out of idea for this scenario.
Any idea?
A dynamic DataContract is an oxymoron. A DataContract is a predetermined and mutually agreed-upon data structure, and dynamic is an object whose structure is not predetermined and thus cannot be agreed-upon, since it can be anything.
It doesn’t appear you actually need to return a dynamic data type, but rather a varying data type. The difference is that a varying data type is one of a set of fixed data types, whereas a dynamic data type is one which does not have a predetermined structure. Since your return value is one of several knows shapes, there is no need to use the "shapeless" (or "freeform") dynamic type, which isn't supported by WCF.
Instead, you could have the [OperationContract] method return a type with a [DataContract] that will act as a wrapper object that has a single data member of type object, and use [KnownType] on the wrapper object to specify the possible types that may be returned inside the wrapper. Since everything inherits from object, there is already a hierarchy in place.
[DataContract]
[KnownType(typeof(OpenIdStatus))]
[KnownType(typeof(string))]
public class ReturnValue
{
[DataMember]
public object Value { get; set; }
}
I think that WCF is going to have issues serializing / deserializing your dynamic type. I would recommend that you set up a contract for the method return based on a defined interface. Alternatively, you could take responsibility for the serialization yourself and make your service return a string. The client will have to have knowledge of what type to de-serialize the string to. There is a similar question on this here:-
How to return dynamic List from WCF HTTP Service

Change datamember name based on method

[DataContract()]
public class Contract
{
.........
Some Properties with DataMembers Attribute.
............
..............
[DataMember(Name = "FirstName")]
public string Name { get; set; }
}
I have above class and I have two web methods (operations)
In 1st web method I want to expose Name as FirstName and in 2nd web method expose Name as LastName.
I don't want to create separate data contracts.
Please tell me how to achieve this?
You can use reflection and change the value of the attribute at runtime depending on which method you in currently. Check out these links on StackOverflow:
How to set attributes values using reflection
Change Attribute's parameter at runtime
But I think the best way would be to either have 2 separate contracts or create a contract with both properties.
You can also implement a surrogate to special-case this type during serialization. As an example, see the Data Contract Surrogate sample.

How can I use internal constructors in public data contracts?

I've got several data contract classes like this:
[DataContract]
public class FooData
{
[DataMember]
public string Name;
// ... many more members
public FooData (string name) // again, many more arguments
{
Name = name;
// ...
}
}
Since FooData is always used to transport Foo objects over the wire, I'd like to add an constructor that takes a Foo object and sets all fields accordingly instead of doing it manually (new FooData (myFoo.Name)).
However, this would require the user of FooData to include the Foo type, which is supposed to be internal to the server. Ordinarily, this issue would be solved by making the constructor taking the Foo internal, but in my case FooData is in a different assembly than Foo.
How should I deal with this? My thoughts so far include using an interface instead of a class to transport data as well, or using an "extension constructor". Any better ideas?
Including the Foo type on the constructor should not be a problem as long as you don't expose that type in a public property marked with DataMember. WCF will take care of serializing only the properties marked with DataMember, so you can internally use your server types in the data contract. However, the client will not able to see that constructor that receives the "Foo" type, so it will have to set all the data in the contract manually
Thanks
Pablo.