WCF Publish/Subscribe and using callbacks to send data to specific users
- by manemawanna
Hello thanks for looking,
I'm working on a project at the moment and have become a little stuck. I'm creating a client server app, which allows a client to subscribe to the server to have messages forwarded to it.
The issue I'm having is that when the client subscribes I wish for them to only recieve updates that relate to them. The system basically passes messages from a SQL server DB which the server monitors. When a new message is recieved the server should only forward the message to the clients that it applys to, based on whos logged on the client machine.
I've had a look and found code samples which sign up for messages to be broadcast across all clients who have subscribed, but not any that show how to identify individual clients and if messages apply to them.
If anyone could help or point me in the right direction it would be appreciated.
You can now find some of my code below:
namespace AnnouncementServiceLibrary
{
[ServiceContract(CallbackContract = typeof(IMessageCallback))]
public interface IMessageCheck
{
[OperationContract]
void MessageCheck();
}
}
namespace AnnouncementServiceLibrary
{
public interface IMessageCallback
{
[OperationContract(IsOneWay = true)]
void OnNewMessage(Mess message);
}
}
public bool Subscribe()
{
try
{
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
//If they dont already exist in the subscribers list, adds them to it
if (!subscribers.Contains(callback))
subscribers.Add(callback);
return true;
}
catch
{
//Otherwise if an error occurs returns false
return false;
}
}
Subscribe/Unsubscribe:
private static readonly List<IMessageCallback> subscribers = new List<IMessageCallback>();
/// <summary>
/// Unsubscribes the user from recieving new messages when they become avaliable
/// </summary>
/// <returns>Returns a bool that indicates whether the operation worked or not</returns>
public bool Unsubscribe()
{
try
{
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
//If they exist in the list of subscribers they are then removed
if (subscribers.Contains(callback))
subscribers.Remove(callback);
return true;
}
catch
{
//Otherwise if an error occurs returns false
return false;
}
}
Finally this at the moment isnt't working as basically when a user subscribes as it loops through I want it to filter based on the users userID:
#region IMessageCheck Members
/// <summary>
/// This method checks for new messages recieved based on those who have subscribed for the service
/// </summary>
public void MessageCheck()
{
//A continuous loop to keep the method going
while(true)
{
//Changes the thread to a sleep state for 2 mins?
Thread.Sleep(200000);
//Go through each subscriber based on there callback information
subscribers.ForEach(delegate(IMessageCallback callback)
{
//Checks if the person who wanted the callback can still be communicated with
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
//Creates a link to the database and gets the required information
List<Mess> mess = new List<Mess>();
List<Message> me;
List<MessageLink> messLink;
AnnouncementDBDataContext aDb = new AnnouncementDBDataContext();
me = aDb.Messages.ToList();
messLink = aDb.MessageLinks.ToList();
//Query to retrieve any messages which are newer than the time when the last cycle finished
var result = (from a in messLink
join b in me
on a.UniqueID equals b.UniqueID
where b.TimeRecieved > _time
select new { b.UniqueID, b.Author, b.Title, b.Body, b.Priority, a.Read, b.TimeRecieved });
//Foreach result a new message is created and returned to the PC that subscribed
foreach (var a in result)
{
Mess message = new Mess(a.UniqueID, a.Author, a.Title, a.Body, a.Priority, (bool)a.Read, a.TimeRecieved);
callback.OnNewMessage(message);
}
}
//If the requesting PC can't be contacted they are removed from the subscribers list
else
{
subscribers.Remove(callback);
}
});
//Sets the datetime so the next cycle can measure against to see if new messages have been recieved
_time = DateTime.Now;
}
}
#endregion