WCF - Sending data to server outside of contract - wcf

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

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.

How do I solve the error that I received when implementing the callback method?

I am currently developing a WCF duplex service and I am trying to implement the callback method in my client app however there is a error of
'App.CallbackHandler' does not implement interface member IPostingServiceCallback.retrieveNotification(Service.Posting)'
the service contract for my service are as follow
[ServiceContract(SessionMode=SessionMode.Required , CallbackContract = typeof(IPostingServiceCallBack))]
public interface IPostingService
{
[OperationContract(IsOneWay = true)]
void postNotification(Posting post);
}
public interface IPostingServiceCallBack
{
[OperationContract]
String retrieveNotification(Posting post);
}
I have generated the proxy and added into the project file of my client and adding the endpoint address into the app.config.
EDIT
The code I have in my client app currently is
public class CallBackHandler : IPostingServiceCallback
{
public void retrieveNotification()
{
//planning to do something
}
}
Your client application needs to implement IPostingServiceCallBack and define the retrieveNotification method.
Say you have a client (not the proxy) that will be consuming your duplex service:
public class MyClient : IPostingServiceCallBack
{
public String retrieveNotification(Posting post)
{
// Implement your logic here
}
}
Note the above is a bare-bones example as a simple illustration. Your client will probably derive from another class as well (depending on whether it's ASP.NET, WinForms, WPF, etc).
Updated
You're still not implementing the method. Your callback interface is:
public interface IPostingServiceCallBack
{
[OperationContract]
String retrieveNotification(Posting post);
}
Your implementation is:
public class CallBackHandler : IPostingServiceCallback
{
public void retrieveNotification()
{
//planning to do something
}
}
You have public void retrieveNotification(), whereas the interface has String retrieveNotification(Posting post). The method signatures don't match.
You need to do:
public class CallBackHandler : IPostingServiceCallback
{
public String retrieveNotification(Posting post)
{
// planning to do something
}
}

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 - CODEGEN: Generating message contract since message FileRequest has headers

I am aware that there is a similar question here with no solution.
I'm working on a WCF streaming service over HTTP.
Here are my MessageContract
[MessageContract]
public class FileRequest
{
#region Message Header
[MessageHeader(MustUnderstand = true)]
public Credential Credentials { get; set; }
#endregion
#region Message body
[MessageBodyMember(Order = 1)]
public FileInfo FileInfo { get; set; }
#endregion
#region Ctor
// ...
#endregion
}
[MessageContract]
public class FileRequestResponse
{
#region Message Header
[MessageHeader(MustUnderstand = true)]
public FileInfo FileHeader { get; set; }
[MessageHeader(MustUnderstand = true)]
public OperationResult<bool> OperationResult { get; set; }
#endregion
#region Message Body
[MessageBodyMember]
public Stream FileStream { get; set; }
#endregion
#region Constructor
// ...
#endregion
}
Here is my ServiceContract
[ServiceContract(Namespace = "https://service.contract.example.com")]
public interface IUpdateService
{
[OperationContract(Action = "GetUpdates")]
OperationResult<List<FileInfo>> GetUpates(ApplicationInfo applicationInfo, Credential credential);
[OperationContract(Action = "GetFile")]
FileRequestResponse FileRequest(FileRequest fileRequest);
}
Now the question is why I am getting this error:
// CODEGEN: Generating message
contract since message FileRequest has
headers
When I add my service reference. The end result is that the service contract wraps the FileRequest operation into a wrapper which I do not want.
public FileInfo FileRequest(Credential Credentials, FileInfo, out OperationResult<bool> OperationResult, out System.IO.Stream FileStream)
NOTE:
I have not checked the "Always generate message contracts" in the service reference.
Set [MessageContract(IsWrapped=true)] for all the message contracts in the service and then try generating the proxy .
You might want to try to use the IsWrapped attribute on the message contract:
[MessageContract(IsWrapped=false)]
Not 100% sure which one you'll need (true or false) but that's one of the options you could try.
Also, another observation: I think it's a bit risky to have a method called FileRequest and a message contract which also is called FileRequest.
The generally accepted best practive would be to have a method GetFile, a request message for that called GetFileRequest and a response message type GetFileResponse. Do not use the same names for different things.