Nested List serialization - wcf

I am having problem transfering my object from WCF to SL3.
interface IComposite {
ICollection<Child_A> Children{ get; set; }
}
[DataContract]
[knownType(typeof(ChildCollection))]
[knownType(typeof(ICollection<Child_A>))]
class Composite : IComposite {
ChildCollection c = null;
[DataMember]
public string Name { get;set;}
[DataMember]
public ICollection<Child_A> Children { get {
return c??(c=new ChildCollection());
} set;}
}
[CollectionDataContract]
class ChildCollection : List<Child_A> {
}
[DataContract]
class Child_A {
[DataMember]
string Name { get;set; }
}
[OperationContract]
Composite GetData(){
var data = new Composite();
data.Children.Add( new Child_A() { Name = "child_a_1" } );
return data;
}
When I call the service from SL3, I get the Composite object but no item in the list. There are other collection in Composite. When I set [DataMember(Order=0/1)] I get error nullreference error on client. And if I remove it, I get error Not Found. I tried KnowType and ServiceKnownType but did not work. I checked svcTrace, it simply says Serialization Error. Where I am doing wrong.
SVC TRACE
The InnerException message was 'Type 'xxxCoverageEntity' with data contract name 'xxxCoverageEntity : http://schemas.datacontract.org/2004/07/xxxBusinessEntities' is not expected. Add any types not known statically to the list of known types
Here xxxCoverageEntity is Child_A in sample

You need to annotate the collection with DataMember or it will not get serialized at all. You will also need to annotate the DataContract with KnownType(typeof(ChildCollection)) as otherwise it doesn't know what type of "thing" the ICollection is and therefore how to serialize it
Similarly you will need to add [DataMember] to Child_A Name property or it will not get serialized

Related

Using DataContract Proxies In WCF

So, I have created a couple of WCF services. Each return lists of a certain type of data contract. However, these data contracts have list properties of other data contracts. I am trying to implement lazy-loading of data contract collections.
What I've thought of is to implement a class at the client that inherits from the data contract with collection properties overriden so the setter and getter methods call the service and get the actual collection items.
My question is: How can I make the base channel to return the class that implements the data contract instead of the actual data contract? how can I control what the base channel returns?
My service client looks like this:
public class ServiceClient : BaseClient<IServiceClient>
{
public IList<DataObject> FindAll()
{
// how to control what base.Channel.FindAll return during deserialization.
return base.Channel.FindAll();
}
}
Note that I don't want to do something like this:
public class ServiceClient : BaseClient<IServiceClient>
{
public IList<DataObject> FindAll()
{
var dtos = base.Channel.FindAll();
var dtoProxies = Mapper.Map<DataObject, DataObjectProxy>();
return dtoProxies;
}
}
I want a way so WCF automatically returns a List<DataObject> which elements are actually of type DataObjectProxy.
Any suggestions on how to do this?
Thanks!
EDIT: Sample DataObject class:
[DataContract]
public class DataObject
{
public virtual List<OtherDomainObject> SubItems { get; set; }
}
public class DataObjectProxy : DataObject
{
public override List<OtherDomainObject> SubItems
{
get { // Custom way to retrieve collection... }
set { // Etc.. }
}
}
First, decorate the DataObjectProxy with the [DataContract] attribute, WCF requires explicit contract identifications for all the types - no matter what you gonna do with them later. Then, set [DataMember] on each and every field (property in your case) of the data contract types that you want to expose to the client.
Finally, add [KnownType(typeof(DataObjectProxy))] attribute on the DataObject class. KnownType defines all sub-types of the given base for polymorphic substitutions on the client.
This should work.
[DataContract]
[KnownType(typeof(DataObjectProxy))]
public class DataObject
{
[DataMember]
public virtual List<OtherDomainObject> SubItems { get; set; }
}
[DataContract]
public class DataObjectProxy : DataObject
{
[DataMember]
public override List<OtherDomainObject> SubItems
{
get { // Custom way to retrieve collection... }
set { // Etc.. }
}
}

WCF callback occurs error when serialize

I am programming a Azure WCF application.
A datacontract defined as below:
[DataContract]
public class UserInfo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public int UserID { get; set; }
[DataMember]
public bool IsOnline { get; set; }
}
then I define a datacontract in my WCF service:
[DataContract(Name="UserInfo")]
public class ServiceUserInfo : UserInfo
{
[IgnoreDataMember]
public ICallback Callback { get; set; }
}
Then in the service contract, it will callback to client, the method as below
private void NoticeUsers(UserInfo currentuser)
{
var users = UserManager.GetAllActiveUsers();
foreach (var user in users)
{
if (user.UserName == currentuser.UserName)
continue;
user.Callback.UpdateUserList(currentuser);
}
}
Actually I pass a ServiceUserInfo object as parameter to the NoticeUsers method. Then an error will occurs as below:
There was an error while trying to serialize parameter http://tempuri.org/:user. The InnerException message was 'Type 'WCFServiceWebRole.ServiceUserInfo' with data contract name 'UserInfo:http://schemas.datacontract.org/2004/07/WCFServiceWebRole' 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.
I am not able to find solution for this issue.Please help.
I think I have found the root cause of the issue, however I do not know why.
The problem is caused by the Namespace attribute of the Service contract.
I didn't set the namespace of my service contract interface and data contract interface. I thought it would be set by default and it won't cause any problem. But actually the issue of this thread is caused by the Namespace attribute. I set a Namespace attribute for both service contract and data contract, of course the same namespace, then it worked. The problem never happens again.
However, I do not know why it caused this issue. If I do not set Namespace, it will be a default value of "http://tempuri.org", isn't it?

Returning subclass of DataContract

I have a DataContract which I use as a return type from a WCF service.
[DataContract]
public NameResult
{
[DataMember]
public string Name { get; set; }
}
However, I want to store additional information on the service side, so I create a subclass:
internal ServiceNameResult : NameResult
{
internal Guid ID { get; set; }
}
However, it seems I am unable to use instances of this as a result value (the error I get on the client isn't very helpful - Unrecognized error 109 (0x6d).
Basically, if I do;
NameResult GetName()
{
NameResult result = {...}
return result;
}
Then it works, but if I do;
NameResult GetName()
{
ServiceNameResult result = {...}
return result;
}
It doesn't. I don't really want to have to copy the properties from the ServiceNameResult to a new NameResult. Hopefully there is a way to make this work?
I've already put [IgnoreDataMember] on the subclass, but that makes no difference.
Thanks.
Here is one way to approach this problem. You could use composition to achieve what you're looking for:
internal class ServiceNameResult
{
object OtherInformation { get; set; }
NameResult Result { get; set; }
}
So your internal service implementation can hold a reference to the client return object as well as additional information, but you don't pollute your interface.
You'll need to define ServiceNameResult as a known type

Serialising classes that implement List<T> for transferring over WCF

I have spent some time writing code for my application assuming that the serialisation bit would be the easiest part of it. Pretty much both sides (client and server) are done and all I need to do is passing a class AccountInfo from the service to the client... The problem is that AccountInfo inherits List and therefore [DataContract] attribute is not valid. I tried using the [CollectionDataContract] attribute but then the class that is received on the other side (client) contains only generic List methods without my custom implemented properties such as GroupTitle...I have worked out a solution for this problem but I don't know how to apply it.
Basically everything works when I make a property instead of inheriting a List but then I can't bind this class to LongListSelector (WP7) because it's not a collection type.
There are three classes I'm on about. AccountInfo that contains multiple instances of: AccountInfoGroup that contains multiple instances of:AccountInfoEntry (this one does not inherit list therefore there are no problems serialising it and all properties are accessible).
Could someone help me using right attributes to serialise and transfer these classes using a WCF method?
Here is the code of 2 of these collection classes:
public class AccountInfo : List<AccountInfoGroup>
{
public AccountInfo()
{
UpdateTime = DateTime.UtcNow;
EntryID = Guid.NewGuid();
}
public bool HasItems
{
get
{
return (Count != 0);
}
private set
{
}
}
public Guid EntryID
{
get;
set;
}
public decimal GetTotalCredit()
{
decimal credit = 0;
foreach (AccountInfoGroup acg in this.Where(item => item.Class == AccountInfoEntry.EntryType.Credit))
{
acg.Where(item => item.ItemClass == AccountInfoEntry.EntryType.Credit).ToList().ForEach(entry =>
{ credit += entry.Remaining; }
);
}
return credit;
}
public bool UsedForCreditComparison = false;
public DateTime UpdateTime { get; private set; }
}
public class AccountInfoGroup : List<AccountInfoEntry>
{
public AccountInfoEntry.EntryType Class
{
get;
private set;
}
public string Title
{
get
{
return AccountInfoEntry.ClassToString(Class);
}
}
public AccountInfoGroup(AccountInfoEntry.EntryType groupClass)
{
this.#Class = groupClass;
}
public bool HasItems
{
get
{
return (Count != 0);
}
private set
{
}
}
}
Thank you for any suggestions... :)
The sample you had is quite painful for WCF in serialization.
What I suggest is you to revised and have a common models for your WCF messages (That means it only contains properties with getter and setter, serialization attributes).
If you have a problem in LongListSelector binding in WP7, you might want to convert the message to the actual type the WP7 object supports to use in binding.

Can I create a WCF Service Contract from a class that I didn't write?

The problem is simple, finding the answer is not (for me at least).
I'm trying to make a WCF service that queries MapPoints FindAddressResults() and returns the answer which I then fetch with Ajax and Javascript.
The problem however is that now I'm getting a FindResults result from FindAddressResults() and I don't know how to expose that as a contract. So I made a wrapper result class.
How can I expose FindResults as a service contract when I don't have access to the source?
[ Edit ]
FindResults is defined as this:
namespace MapPoint
{
[TypeLibType(4288)]
[Guid("188084CF-DB96-482B-97A6-2571DF9BEF81")]
public interface FindResults : IEnumerable
{
[DispId(100663313)]
Application Application {get; }
[DispId(100663321)]
int Count {get; }
[DispId(-803)]
Map Parent {get; }
[DispId(100672001)]
GeoFindResultsQuality ResultsQuality {get; }
[DispId(0)]
object this[ref object Index] {get; }
[TypeLibFunc(64)]
[DispId(-4)]
IEnumerator GetEnumerator();
}
}
Can you just extend the class you want and add the contract attribute?
[ServiceContract]
public MyFindResults : FindResults
{
[DataMember]
public new string String1
{
get
{
return base.String1;
}
}
}