Common WCF Response Handler? - wcf

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.

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

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.

DataContract composite Class

I have a problem with serialization composite class (using WCF Service).
here my class in namespace1 (it is not in service namespace) :
[DataContract]
public class UpData
{
[DataMember]
public double Version ;
public UpData()
{
this.Version = -1;
}
}
In my Service namespace (in interface) I deсlare this procedure :
ArrayList GetDownloadPath(Dictionary<string,string> lib1, Dictionary<string,string> lib2);
ArrayList contains UpData objects.
I have error(
How will be right to send ArrayList of UpData objects? (may be specific DataContract?)
Thanks a lot!
I'm not sure if ArrayList is serializable by default. Using a generic list could solve your problem:
[OperationContract]
List<UpData> GetDownloadPath(Dictionary<string,string> lib1, Dictionary<string,string> lib2);
EDIT: I think you also need to specify a getter and setter for your Version property, i.e.
[DataContract]
public class UpData
{
[DataMember]
public double Version { get; set; }
public UpData()
{
this.Version = -1;
}
}
More info here.

Wcf inhereted models

[DataContract]
Base
{
[DataMember]
public int Id {get;set;}
}
[DataContract]
A : Base
{
[DataMember]
public string Value {get;set;}
}
[ServiceContract]
interface IService
{
[OperationContract]
void SetValue (Base base);
}
is there a way to use the service like the following style:
new Service ().SetValue (new A ());
You tagged this WCF so I assume you want to use it.
You need to connect to the endpoint using the ChannelFactory and then open the channel.
This will not work:
new Service ().SetValue (new A ());
You need to do smth. like this:
using (var scf = new ChannelFactory< IService >(<Binding>,<EndpointAddress>)
{
IService proxy = scf.CreateChannel();
proxy.SetValue(new (A));
}
This will return you a proxy object that implements the IService interface. You can call the SetValue on this object.
As well as changing the way you're calling the service as indicated by #Flo, you'll also need to make a small change to prepare the Data Contract Serializer to deal with the inheritance hierarchy.
The easiest way of doing this is decorating Base with the KnownTypeAttribute. Like this,
[DataContract]
[KnownType(typeof(A))]
Base
{
[DataMember]
public int Id {get;set;}
}
[DataContract]
A : Base
{
[DataMember]
public string Value {get;set;}
}

WCF - Sending data to server outside of contract

I have a WCF service with a client application. I have complete control over both the client and server implementation. I have hundreds of methods in the WCF contract which need a piece of information supplied by the client. Instead of modifying hundreds of methods, is there a way I can send specific data from the client with every call to the service, possibly somewhere in the channel?
Maybe when the client is setting up the proxy before making the call, it can store this data somewhere in an internal property of the proxy... the data would then get sent to the server and from within the service method I could inspect the OperationContext or some other piece of memory to get this data back and use it?
Any ideas?
It sounds like you are wanting something like headers like with SOAP webservices. I'm not a WCF expert, but this looks like the WCF equivalent.
It shouldn't actually be that hard. The best way I can think of is to write an IClientMessageInspector that adds a SOAP header into the Message.Headers in its BeforeSendRequest method.
See e.g. http://weblogs.asp.net/paolopia/archive/2007/08/23/writing-a-wcf-message-inspector.aspx
You can't do this trivially. It will take some work.
It's true that SOAP Headers are the perfect way to pass out-of-band data to and/or from a service. But you already have your contract defined, and adding headers will change the contract.
I believe you'll have to start using message contracts.
Original:
[DataContract]
public class ComplexObject
{
[DataMember(Name = "Id")]
public int Id;
[DataMember]
public string Name;
}
[ServiceContract()]
public interface IMyContract
{
void MyOperation(ComplexObject co);
}
public class MyService : IMyContract
{
#region Implementation of IMyContract
public void MyOperation(ComplexObject co)
{
// use co.*
}
#endregion
}
Using Message Contracts:
[DataContract]
public class ComplexObject
{
[DataMember(Name = "Id")]
public int Id;
[DataMember]
public string Name;
}
[DataContract]
public class MyHeader
{
[DataMember]
public string UserName;
[DataMember]
public string Password;
}
[DataContract]
public class OutputHeader
{
[DataMember]
public string Token;
}
[MessageContract]
public class MyOperationRequest
{
[MessageHeader]
public MyHeader Authentication;
[MessageBodyMember]
public ComplexObject TheObject;
}
[MessageContract]
public class MyOperationResponse
{
[MessageHeader]
public OutputHeader OutputHeader;
}
[ServiceContract()]
public interface IMyContract
{
MyOperationResponse MyOperation(MyOperationRequest request);
}
public class MyService : IMyContract
{
public MyOperationResponse MyOperation(MyOperationRequest request)
{
// use request.TheObject.*
// Can also read request.Authentication.*
return new MyOperationResponse
{ OutputHeader = new OutputHeader { Token = "someToken" } };
}
}