Author: Jonio, Dennis
I make absolutely no attempt here to explain why I have done the things the way I have done them in relationship to the grand scheme of WCF. There is just too much to explain and you really should get the book and improve on what I have done. I stopped a long time ago in trying to force Map3d to do multi-threading. As it turns out this is not debilitating at all, just use a Form.
The following are my concrete classes for the WCF interfaces found in the previous article. Making no value judgments, you do have to be impressed with how much Microsoft has done in producing the “behind the scenes” transport functionality. Since I wanted “required, reliable sessions with binary transport” I have coded towards the NetTcpBinding and the NetNamedPipeBinding.
As you can see there are two(2) methods for getting data to the service and the service has one(1) method to send data back to the client. During research I happened upon this multiple client subscription concept with a simple Guid identifier. I desperately wanted some kind of "session identifier" that was all ready in place, generic and robust. If you do the reading you will discover WCF has the concept of SessionId but in my mind's eye it is too crippled to be of any use for my purpose. This subscription paradigm struck me as a good, simple and straightforward idea.
The service itself.
Source code (C#):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace DplXByteSrvcs
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class ByteSrvcWCallbackImpl : IByteSrvcWCallback
{
public delegate void DataIsReady(byte[] hotData);
public DataIsReady DataReady = null;
public delegate void DQDataIsReady(string destinationQ, byte[] hotData);
public DQDataIsReady DQDataReady = null;
public delegate void GotControlPacket(byte[] hotPacket);
public GotControlPacket OnGotControlPacket = null;
public readonly DictionarySrvcClients =
new Dictionary();
public void ControlPacket(byte[] ba)
{
int rtnval = 0;
if (ba != null)
rtnval = ba.Length;
if (OnGotControlPacket != null)
OnGotControlPacket(ba);
IByteSrvcCallback callback = OperationContext.Current.GetCallbackChannel();
if (!SrvcClients.ContainsValue(callback))
{
Guid clientId = Guid.NewGuid();
if (callback != null)
{
lock (SrvcClients)
{
SrvcClients.Add(clientId, callback);
}
}
}
}
public int PipedIn(byte[] data)
{
int rtnval = 0;
if (data != null)
rtnval = data.Length;
if (DataReady != null)
DataReady(data);
return rtnval;
}
public int DQPipedIn(string destinationQ, byte[] data)
{
int rtnval = 0;
if (data != null)
rtnval = data.Length;
if (DQDataReady != null)
DQDataReady(destinationQ, data);
return rtnval;
}
Guid IByteSrvcWCallback.Subscribe()
{
IByteSrvcCallback callback =
OperationContext.Current.GetCallbackChannel();
Guid clientId = Guid.NewGuid();
if (callback != null)
{
lock (SrvcClients)
{
SrvcClients.Add(clientId, callback);
}
}
return clientId;
}
void IByteSrvcWCallback.UnSubscribe(Guid clientGID)
{
lock (SrvcClients)
{
if (SrvcClients.ContainsKey(clientGID))
{
SrvcClients.Remove(clientGID);
}
}
}
void IByteSrvcWCallback.NoOpButKeepAlive() { }
}//EOC
}//EONS
You will discover as I did that the communications piece is really all about the client. Nothing much happens without them.
Now for the Client the callback class.
Source code (C#):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DplXByteSrvcs
{
public class ByteSrvcCallbackImpl : IByteSrvcCallback
{
public delegate void GotControlPacket(byte[] hotPacket);
public GotControlPacket OnGotControlPacket = null;
private byte[] m_ba;
public byte[] ControlPacket
{
get { return m_ba; }
}
public void SentControlPacket(byte[] ba)
{
m_ba = ba;
if (OnGotControlPacket != null)
OnGotControlPacket(ba);
}
}
}
No comments:
Post a Comment