I have:
[DataContract]
public class A
{
[DataMember]
public int X { get; set; }
}
[DataContract]
[KnownType(typeof(Derived<A>))]
public class Base {}
[DataContract]
public class Derived<T>: Base {
[DataMember]
public T Data {get; set; }
}
Service method returns IEnumerable of Base class containing object of Derived class.
Auto-generated WCF client retrieves data and correctly detects type and creates instances of the Derived class, but Derived.Data.X is not mapped, i.e. has 0. The soap message received is correct.
Any ideas why the generic property of the derived class is not correctly mapped from the soap message in the client?
I strongly recommend you to avoid generics in service contracts. SOA world is not friendly with generic type in the service contract. Please look problems reported by others:
Error when updating service reference.The URI prefix is not recognized
WCF. Service generic methods
WCF generic property is not mapped in derived class
http://social.msdn.microsoft.com/Forums/vstudio/en-US/2a9a2fc6-9e01-4112-8948-4192c516c6e7/how-to-use-generics-in-wcf-service
Related
One of my WCF endpoints has this method:
GetData(DataTable dt)
I tried to create a class on the client that inherits from the DataTable class
public class ExtendedDataTable : DataTable{
//...implementation
}
and pass it along with the endpoint call:
GetData(new ExtendedDataTable());
Then I got the SerializationException. Accordingly to the error, it suggests that I use either DataContractResolver or the KnownType attribute.
I don't want to use the KnownType, because I shouldn't have to update the endpoint every time someone decides to inherit my DataContract. I can't write any DataContractResolver, because I didn't extend the exact structure of the DataTable class. Is it possible to to extend a DataContract from the client?
If so, what's the best practice?
Thanks!
I don't recommend using the Datatable, which makes it easy for WCF to have problems with client and server serialization, such as the need to specify a table name. It is best to use a custom data type, we can use the inheritance type with the KnownType attribute.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-known-types
On my side, I can't use the inherited Datatable, while I could use an arbitrary custom class by using Knowntype attribute.
Please refer to my code segments.
[DataContract]
[KnownType(typeof(Product))]
public class MyData
{
[DataMember]
public ProductBase Product { get; set; }
}
[DataContract]
public class ProductBase
{
[DataMember]
public int ID { get; set; }
}
[DataContract]
public class Product : ProductBase
{
[DataMember]
public string Name { get; set; }
}
You can try to inherit DataTable and explicitly use DataContract attribute to declare it's name as "DataTable".
But I'm not sure about purpose of this replacement. Server side will see only what is related to original data contract. Even when new properties gets serialized, deserializatin will only work for server side properties. Unless some custom deserialization will be provided.
In all scenarios, using DataTable is not good idea at all as Abraham Qian already pointed out.
I have a question about the [DataContract] attribute.
I have written my code like below: here I am not using [DataContract] attribute for my test class.
class test
{
[Datamember]
public string Strproperty
{
get;
set;
}
[Datamemer]
public string Strproperty2
{
get;
set;
}
}
class checktotal:Iservice
{
public string testmethod(test obj)
{
return obj.Strproperty+Strproperty2;
}
}
For that I am sending data from client I am getting the values correctly.
Here is it necessary to use [DataContract] attribute for that test class?
If I removed [Datamember] for test class property is getting error while sending from client. But I am not getting any errors even if I am not using the [DataContract] attribute.
Please give me a brief explanation with example so that I can understand when to give that attribute and when do not give that attribute.
Thanks,
Satya Pratap.
The DataContractSerializer can deal with classes that do not have the DataContract attribute if they provide a default constructor. See the MSDN documentation for more details.
As of .NET 3.5 Service Pack 1, you can omit (not use) the [DataContract] and [DataMember] attributes. If you do that, then the DataContractSerializer in WCF will behave just like the XML serializer - it will serialize all public properties only.
I prefer to use [DataContract] and [DataMember] explicitly anyway - it gives me the opportunity to specify options (like the data contract's XML namespace, the order of the [DataMember]) and it lets me e.g. also exclude certain properties from serialization.
As soon as you start using [DataMember] on one property, then only those properties decorated with a [DataMember] will be looked at for the WCF serialization.
I have a class Car
public class Car
{
private Member _owner;
public string OwnerName
{
get { return _owner.Name; }
}
public Car(Member owner)
{
_owner = owner;
}
}
I'm using it both at Silverlight application and wcf service
So, at application I call WCF service to give me instance of car class, but when I get it at application, I see that _owner is empy.
I know that it is empty because of private, but how can I deal with it?
I'm using this class in my app as model (MVVM) if it could helps :/
For a start none of your properties are marked as DataMembers. The class isn't marked as a DataContract. If this is getting returned from a WCF service I would expect to see:
[Serializable]
[DataContract]
public class Car
{
private Member _owner;
[DataMember]
public string OwnerName
{
//getter
//setter
}
etc..
}
Does Member have to be private? Could it be converted into a property?
Keep in mind that a [DataMember] property needs both a set and a get (so that WCF can read into and from the object).
http://msdn.microsoft.com/en-us/library/ms733127.aspx
From a WCF serialization point of view, your Car class actually looks something like this to the WCF service:
public class Car
{
public string OwnerName { get; set; }
//other public properties here....
}
The WCF serializer uses the .NET class definition as a template for serializing its contents as a simple data transfer object. When the WCF service sends back a Car instance, only the public properties will contain values. The serializer ignores all methods in the class. Also, later versions of WCF don't require the DataContract/DataMember attribute markup.
The _owner variable is never initialized because it is not part of the public properties of the Car class. You'll need to modify the structure of the Car class (maybe add a public Owner property of type Member) to get all the data sent from the WCF service to your client.
When you are using the default Data Contract Serializer with WCF services it serializes and deserializes only the public properties of the class. Also another thing to note is that while deserializing the object graph the constructor is not called. You can have a public property with getter and setter.
Here is a very nice article by Jeremy Likeness explaining the problem similar to yours. From Architecture as well as best practices point of view you can use a POCO class generally called as DTO (Data Transfer Object) when transferring objects between the service layer and the clients.
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
Can I have a data contract of this shape??
[DataContract]
public class YearlyStatistic{
[DataMember]
public string Year{get;set;}
[DataMember]
public string StatisticName {get;set;}
[DataMember]
public List<MonthlyStatistic> MonthlyStats {get;set}
};
I am assuming here that class MonthlyStatistic will also need to be a DataContract. Can you do this in a web service?
To use the same model for web services, mark your class as Serializable use the XmlRoot and XmlElement in the System.Xml.Serialization namespace. Here is a sample using your example:
[Serializable]
[XmlRoot("YearlyStatistic")]
public class YearlyStatistic
{
[XmlElement("Year")]
public string Year { get; set; }
[XmlElement("StatisticName")]
public string StatisticName { get; set; }
[XmlElement("MonthlyStats")]
public List<MonthlyStatistic> MonthlyStats { get; set; }
}
You will have to do the same thing for your complex object properties of the parent object.
Yep, thats standard WCF serialization right there. Are you trying to say the MonthlyStats collection has a property called WeeklyStats, or that each individual MonthlyStatistic has a WeeklyStat collection? If its the former, that doesnt work in WCF natively. You will have to do some fiddling in order to get it to work. If its the latter, its perfectly fine.
Yes, you can send the data contract you mentioned above back and forth from a WCF service. Like you said, MonthlyStatistic and all its members will have to be defined as data contracts themselves or be built in types (like strings).
You can even send and receive more complex types like when you have a base class but want to send or receive an object of a derived class (you would do that using the KnownType attribute). While receiving (de-serialization), from Javascript, there's a trick using which you have to specify the type for WCF. If you are interested, feel free to ask.