Hello, i want to build a simple winform chat application using wcf. There will be a login form, a form to select the channel and the chat form. I figured it out like this:
- MembershipService -> login, logout, register
- ChatService ->JoinChatChannel, LeaveChannel, SendPublicMessage, SendPrivateMessage
MembershipService:
public class MembershipService : IMembershipService
{
private static object syncObj = new object();
private static List<OnlineUser> onlineUsers = new List<OnlineUser>();
private User user;
public bool Login(User user)
{
using (WarDatabaseEntities model = new WarDatabaseEntities())
{
var users = model.Users;
foreach (var u in users)
{
if (u.Username == user.Username && u.Password == user.Password)
{
lock (syncObj)
{
this.user = user;
onlineUsers.Add(new OnlineUser
{
User = user,
Channel = string.Empty,
Callback = OperationContext.Current.GetCallbackChannel<IChatCallback>()
});
}
return true;
}
}
}
return false;
}
public void Logout(User user)
{
throw new NotImplementedException();
}
public bool Register(User user, out RegistrationStatus status)
{
using (WarDatabaseEntities model = new WarDatabaseEntities())
{
if (user.ChangeTracker.State == ObjectState.Added)
{
foreach (var u in model.Users)
{
if (u.Username == user.Username)
{
status = RegistrationStatus.UsernameAlreadyExists;
return false;
}
}
model.Users.AddObject(user);
model.SaveChanges();
user.AcceptChanges();
status = RegistrationStatus.UserCreated;
return true;
}
else
{
status = RegistrationStatus.RegistrationException;
return false;
}
}
}
internal static OnlineUser[] SetChannelAndGetUsers(string channel, User user)
{
OnlineUser[] onliners;
lock (syncObj)
{
OnlineUser u = onlineUsers.Single(z => z.User.Username == user.Username);
u.Channel = channel;
onliners = (from o in onlineUsers
where o.Channel == channel
select o).ToArray();
}
return onliners;
}
internal static IChatCallback GetChatCallback(User to)
{
IChatCallback targetCallback;
lock (syncObj)
{
targetCallback = (from o in onlineUsers
where o.User.Username == to.Username
select o.Callback).ToArray()[0];
}
return targetCallback;
}
internal static IChatCallback[] GetChatCallbacks(User frm, string channel)
{
IChatCallback[] targetCallbacks;
lock (syncObj)
{
targetCallbacks = (from o in onlineUsers
where o.Channel == channel && o.User.Username!=frm.Username
select o.Callback).ToArray();
}
return targetCallbacks;
}
}
ChatService:
public class ChatService : IChatService
{
public User[] JoinChatChannel(string channel, User user)
{
OnlineUser[] onliners = MembershipService.SetChannelAndGetUsers(channel, user);
foreach (OnlineUser onliner in onliners)
{
onliner.Callback.OnUserEntered(user);
}
return (from o in onliners
select o.User).ToArray();
}
public void SendPrivateMessage(User to, string message)
{
IChatCallback targetCallback = MembershipService.GetChatCallback(to);
targetCallback.OnPrivateMessageReceived(to, message);
}
public void SendPublicMessage(User from, string message, string channel)
{
IChatCallback[] targetCallbacks = MembershipService.GetChatCallbacks(from,channel);
foreach (IChatCallback callback in targetCallbacks)
{
callback.OnPublicMessageReceived(from, message);
}
}
public void LeaveChatChannel(User who, string channel)
{
IChatCallback[] targetCallbacks = MembershipService.GetChatCallbacks(who, channel);
foreach (IChatCallback callback in targetCallbacks)
{
callback.OnUserLeft(who);
}
}
}
And the helper class to hold the online user, the channel he is on and the callback for the user, used to notify the others when he joins, leaves or sends a message
public class OnlineUser
{
public User User { get; set; }
public string Channel { get; set; }
public IChatCallback Callback { get; set; }
}
MembershipService holds the online users and their callbacks and ChatService must access this callection. QUESTION: is this the correct way to share data between services?