Using DataContract Proxies In WCF - 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.. }
}
}

Related

Common WCF Response Handler?

I have a WCF Client, and the Endpoint has just been upgraded with a new method (OperationContract). I want to write a common method to handle the response from this new method as well as from the existing method at the endpoint.
I am trying to create a "Base" response class and adding common properties to it provided by the WCF endpoint, but I notice in my handler method, the properties are not being retained.
The code for the class I want all responses to inherit from looks like this :
public class ResponseBase
{
public string[] ItemsReturned;
public bool ItemsWereAvailable;
}
So I add partial declarations to get this onto the objects in the endpoint.
public partial class RetrieveResponse :ResponseBase
{
}
public partial class RetrieveResponse2 :ResponseBase
{
}
This way I have a handler method that just accepts "ResponseBase" as its input.
Am I doing this all wrong?
Any class whose instances will be return values and/or parameters of an operation contract should be decorated with the DataContract attribute, and the properties, as DataMembers:
[DataContract]
public class ResponseBase
{
[DataMember]
public string[] ItemsReturned { get; set; }
[DataMember]
public bool ItemsWereAvailable { get; set; }
}
http://msdn.microsoft.com/en-us/library/ms733127.aspx
If they are not, the DataContractSerializer doesn't serialize them.

Passing List<T> as parameter to WCF service operation

I have a WCF operation contract which looks like this:
public void SavePersons(List<Person> list, bool IsSelected)
{
}
I am passing it a strongly typed list of Person objects (List<Person>) in my client. However, I am getting a bad request 400 message when calling the service. What am I doing wrong?
May I suggest you create you create a contract to encapsulate the parameters like so:
public void SavePersons(PersonCollectionContract Request)
{
...
}
[DataContract]
public class PersonCollectionContract
{
[DataContract]
public List<Person> People { get; set; }
[DataContract]
public bool IsSelected { get; set; }
}
[DataContract]
public class Person
{
...
}
I was facing a similar problem in passing a List<Health> of class Health type as a parameter to a wcf service method. I created a data contract in wcf service as below:
[DataContract]
public class Health
{
...
}
Defined a method in wcf service class such as:
public string GetData(List<Health> healthValues)
In my client application, while configuring/updating the service, I followed these steps:
Add/Update URL
Under Data Type (in Advanced), selected option, Collection type: System.Collection.Generic.List
And finally, I created a list and added the code in client as follows:
List<WcfService.Health> listHealth = new List<WcfService.Health>();
WcfService.Health h = new WcfService.Health();
.
.
listHealth.Add(h);
WcfService.Service1Client s = new WcfService.Service1Client();
string str = s.GetData(listHealth);
This solved my purpose and I was able to send the data as a list through wcf service.

WCF DataContract - treating derived class as base class for serialization

I have a simple data contract:
[DataContract]
public class MyData
{
[DataMember]
public string AwesomeData { get; set; }
}
And service contract:
[ServiceContract]
public interface IMyDataService
{
[OperationContract]
MyData GetAwesomeData();
}
In the server-side assembly, I create a derived class for doing processing:
public class MyDataWithInnerds: MyData
{
public MyDataWithInnerds(object intializationStuff)
{
AwesomeData = Hypermaxulate(initializationStuff);
}
}
and the service implementation:
public class MyDataService: IMyDataService
{
public MyData GetAwesomeData()
{
return new MyDataWithInnerds(HupnerRayvakManager.GetInitializationStuff());
}
}
MyDataWithInnerds is just the functional implementation of the purely data contract MyData.
Is there anyway without decorating MyData and referencing MyDataWithInnerds to tell the serializer to serialize MyDataWithInnerds as MyData? The assembly with MyData is also given to clients. I don't want the server-side only MyDataWithInnerds to be referenced.
I don't need to de-serialize it to MyDataWithInnerds. I'm guessing I'm going to need to clone the MyDataWithInnerds instance to a MyData instance so it doesn't have any type information associated with MyDataWithInnerds, but it would be really efficient to not have to do that and just let the serializer know "I know this is a MyDataWithInnerds, but you can just treat it like the base MyData"
Thanks,
Mike
EDIT
I was able to add the following to my config file on the server:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyClientLib.MyData, MyClientLib">
<knownType type="MyServerLib.MyDataWithInnerds, MyServerLib"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
And this makes the serialization work properly.
It just leaves two side questions:
In my JSON serialization, I end up with a "__type" member that contains the derived class type. Can I remove that?
Is there a declarative way to do, on the server objects (not MyData), what I have done in configuration (adding KnownType's)?
Thanks2,
Mike
In the end, I created a copy constructor for my base class and instead of returning the derived class (as the base class), I return new base(derived).
[DataContract]
public class MyData
{
[DataMember]
public string AwesomeData { get; set; }
public MyData(MyData obj)
{
AwesomeData = obj.AwesomeData;
}
}
The service implementation then becomes:
public class MyDataService: IMyDataService
{
public MyData GetAwesomeData()
{
MyDataWithInnerds data =
new MyDataWithInnerds(HupnerRayvakManager.GetInitializationStuff());
return new MyData(data);
}
}
In the simplistic example it looks like overkill, but in the actual application, it works out decently -- without having extra configuration and not emitting extraneous serialized data.

Error while running WCF service library

I have built a WCF service library, I have added reference to few 3rd party dll's. This is my interface
[ServiceContract]
public interface IService1
{
[OperationContract]
3rdpartyreturntype GetObj(System.Windows.Controls.Control txtcontrol);
}
// Use a data contract as illustrated in the sample below to add composite types to service operations
[DataContract]
public class nclass
{
[DataMember]
public System.Windows.Controls.Control txtcontrol
{
get { return txtcontrol; }
set { txtcontrol = value; }
}
[DataMember]
public 3rdpartyreturntype nobj
{
get { return vuiobj; }
set { vuiobj = value; }
}
[DataMember]
public System.Windows.Input.TouchDevice tchdev
{
get { return tchdev; }
set { tchdev = value; }
}
}
and I have implemented the above interface. When I run the service I get the below error, can anyone help me out?
type 'System.Windows.Input.TouchDevice' cannot be serialized. Consider
marking it with the DataContractAttribute attribute, and marking all
of its members you want serialized with the DataMemberAttribute
attribute.
if you want a complex type like a class to be serialized you have to declare each of its members as data member and class as datacontract.
In this case touch device is the complex type(class) so you need to mark all of its members as datamembers and class as datacontract.
but as i can see from type that it belongs to system.windows.input the class may not be serialized. hence you cannot use this as a data member.
If you are using only a set of members belonging to touchDevice class, you can create your own class which will map only the set of touchdevice members which can be serialized. and decorate this new class with datacontract and datamember attributes.
It would appear that the type "System.Windows.Input.TouchDevice" is itself not marked as serializable or a DataContract.
Instead of trying to pass the TouchDevice and the Control directly like that, maybe you can just pass the properties you care about. I'm guessing in the case of the TextControl you just care about the Text value. And for the TouchDevice, maybe the source and target control name?

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;
}
}
}