Reputation: 1314
I am trying to create a WCF service, that has a webHttpBinding
endpoint (for Java clients) and a netTcpBinding
endpoint (for .NET clients).
With the netTcpBinding
endpoint I would like to be able to use callbacks in order to be alerted to events, but when I try to configure this, WCF complains because the service also has the webHttpBinding
endpoint, which doesn't support callbacks.
Is there a way of having the callback utilised by one endpoint but not another?
Upvotes: 2
Views: 859
Reputation: 87238
No, the binding will validate that it can honor the contract; if the contract is a duplex contract (i.e., it specifies a CallbackContract
) but the binding can't do duplex, then it will throw during validation.
What you can do is to have a base contract which is used by the webHttpBinding
endpoint, and another contract (this time a duplex one), derived from the first, which is used by the netTcpBinding
endpoint.
The code below shows an example of such contract arrangement.
public class StackOverflow_7341463
{
[ServiceContract]
public interface ICalc
{
[OperationContract, WebGet]
int Add(int x, int y);
[OperationContract, WebGet]
int Subtract(int x, int y);
[OperationContract, WebGet]
int Multiply(int x, int y);
[OperationContract, WebGet]
int Divide(int x, int y);
}
[ServiceContract(CallbackContract = typeof(ICalcNotifications))]
public interface INotifyingCalc : ICalc
{
[OperationContract]
void Connect();
[OperationContract]
void Disconnect();
}
[ServiceContract]
public interface ICalcNotifications
{
[OperationContract(IsOneWay = true)]
void OperationPerformed(string text);
}
public class Service : INotifyingCalc
{
static List<ICalcNotifications> clients = new List<ICalcNotifications>();
#region ICalc Members
public int Add(int x, int y)
{
this.NotifyOperation("Add", x, y);
return x + y;
}
public int Subtract(int x, int y)
{
this.NotifyOperation("Subtract", x, y);
return x - y;
}
public int Multiply(int x, int y)
{
this.NotifyOperation("Multiply", x, y);
return x * y;
}
public int Divide(int x, int y)
{
this.NotifyOperation("Divide", x, y);
return x / y;
}
#endregion
#region INotifyingCalc Members
public void Connect()
{
var callback = OperationContext.Current.GetCallbackChannel<ICalcNotifications>();
clients.Add(callback);
}
public void Disconnect()
{
var callback = OperationContext.Current.GetCallbackChannel<ICalcNotifications>();
clients.Remove(callback);
}
#endregion
private void NotifyOperation(string operationName, int x, int y)
{
foreach (var client in clients)
{
client.OperationPerformed(string.Format("{0}({1}, {2})", operationName, x, y));
}
}
}
class MyCallback : ICalcNotifications
{
public void OperationPerformed(string text)
{
Console.WriteLine("Operation performed: {0}", text);
}
}
public static void Test()
{
string baseAddressTcp = "net.tcp://" + Environment.MachineName + ":8008/Service";
string baseAddressHttp = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddressHttp), new Uri(baseAddressTcp));
host.AddServiceEndpoint(typeof(ICalc), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.AddServiceEndpoint(typeof(INotifyingCalc), new NetTcpBinding(SecurityMode.None), "");
host.Open();
Console.WriteLine("Host opened");
var factory = new DuplexChannelFactory<INotifyingCalc>(
new InstanceContext(new MyCallback()),
new NetTcpBinding(SecurityMode.None),
new EndpointAddress(baseAddressTcp));
var proxy = factory.CreateChannel();
proxy.Connect();
Console.WriteLine("Proxy connected");
Console.WriteLine(new WebClient().DownloadString(baseAddressHttp + "/Add?x=4&y=7"));
Console.WriteLine(new WebClient().DownloadString(baseAddressHttp + "/Multiply?x=44&y=57"));
Console.WriteLine(new WebClient().DownloadString(baseAddressHttp + "/Divide?x=432&y=16"));
proxy.Disconnect();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
((IClientChannel)proxy).Close();
factory.Close();
host.Close();
}
}
Upvotes: 4