silverlightwcf:使用SilverLight构建插件式应用程序( 8) —聊天插件Duplex WCF的实现

  这次是个在线聊天插件插件参考了MSDN中Duplex WCF服务实现和网上些聊天基本可以实现用户登录和聊天如果用户不存在就保存聊天数据到数据库等用户下次登陆时候读入

  这个是聊天时候图例:

使用SilverLight构建插件式应用<img src='/icons/63191chengxu.gif' />( 8) —聊天插件Duplex WCF<img src='/icons/63191de.gif' />实现

  1: 定义聊天时候传输聊天数据实体这个所有WCF都是没什么特殊代码如下:

  [DataContract]

public ChatMessage
{
  [DataMember]
  public From;
  [DataMember]
  public To;
  [DataMember]
  public Type;//1:Text;2:Url;3:File;4:Image;5:Audio;6:Video;0:None;-1:;-2:Heart;
  [DataMember]
  public Data;
  [DataMember]
  public Content;
}


  这样用户每次聊天就发送使这个数据了这是服务器端定义

  2:定义回调时候接口:

[ServiceContract]
public erface IWSChatClient
{
  [OperationContract(IsOneWay = true)]
  void Receive(Message Message);
}


  3:定义Duplex WCF服务实现

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract(Namespace = "WindCloud", SessionMode = SessionMode.Required, CallbackContract = typeof(IWSChatClient))]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public WSChatService
{
   Dictionary<, IWSChatClient> chatClients = Dictionary<, IWSChatClient>;
   List<> m_NameList = List<>;
  private Object syncObj = Object;
   guestIndex = 1;
   name = "";
}


  这个WCF服务并没有从接口继承过来而是直接地实现这个和MSDN上边稍微有点差异的所以这样做将来可以使用Forms验证模式来验证用户这是个主要原因将来说到权限时候我会具体说到这

  4: 接受心跳信息:

  /// <summary>
  /// 获取心跳信息更新连接
  /// </summary>
  /// <param name="receivedMessage"></param>
  [OperationContract(IsOneWay = true)]
  public void Heart(Message receivedMessage)
  {
    ChatMessage chatMessage = receivedMessage.GetBody<ChatMessage>;
    IWSChatClient chatclient = OperationContext.Current.GetCallbackChannel<IWSChatClient>;
     (chatClients.ContainsKey(chatMessage.From))
    {
      chatClients[chatMessage.From] = chatclient;
      //
      chatMessage.From = "Server";
      chatMessage.To = chatMessage.From;
      chatMessage.Type = -2;
      Message Message = Message.CreateMessage(MessageVersion.Soap11, "WindCloud/WSChatService/Receive", chatMessage);
      chatclient.Receive(Message);
    }
  }


  客户端会定时发送心跳信息到服务器端如果客户端有段时间没有发送心跳信息这就是说客户端掉线或者其他原因了

  5:用户进入聊天室:

//进入聊天室
  [OperationContract(IsOneWay = true)]
  public void Join(Message receivedMessage)
  {
    bool userAdded = false;
    Message Message;
    ChatMessage chatMessage = receivedMessage.GetBody<ChatMessage>;
    IWSChatClient chatclient = OperationContext.Current.GetCallbackChannel<IWSChatClient>;
    ChatMessage sendChatMessage = ChatMessage;
    sendChatMessage.From = "Server:";
    sendChatMessage.Data = "Service:请等待...";
    sendChatMessage.Type = -1;
    //
    lock (syncObj)
    {    
       (!chatClients.ContainsKey(chatMessage.From) && chatMessage.From != "" && chatMessage.From != null)
      {
        chatMessage.Data = "Service:开始添加用户...";
        Message = Message.CreateMessage(MessageVersion.Soap11, "WindCloud/WSChatService/Receive", chatMessage);
        chatclient.Receive(Message);
        this.name = chatMessage.From;
        m_NameList.Add(chatMessage.From);
        chatClients.Add(chatMessage.From, chatclient);
        userAdded = true;
      }
      
      {
        ChatMessage cm = ChatMessage;
        cm.From = "Server:";
        cm.Data = "Service:User:" + chatMessage + "加入失败用户已存在";
        Message = Message.CreateMessage(MessageVersion.Soap11, "WindCloud/WSChatService/Receive", cm);
        //
        chatclient.Receive(Message);
        ;
      }
      //发送留言
      ChatBLL bll = ChatBLL;
      List<ChatMessage> cms = bll.GetChats(chatMessage.From);
      foreach (ChatMessage cm in cms)
      {
        SendMessageToClient(cm);
      }
      //删除留言
      bll.Delete(chatMessage.From);
    }
     (userAdded)
    {
       text2 = "Service:User:" + chatMessage + " is already Joined";
      ChatMessage cm = ChatMessage;
      cm.From = "Server:";
      cm.Data = text2;
      SendMessageToClient(cm);
    }
  }


  用户加入聊天室的后加入到用户队列中同时从用户聊天数据库读入其他用户给当前用户留言并删除留言

  6:用户说话这是平常直要使用思路方法接受用户聊天信息:

 /// <summary>
  /// 聊天
  /// </summary>
  /// <param name="receivedMessage"></param>
  [OperationContract(IsOneWay = true)]
  public void Say(Message receivedMessage)
  {
    IWSChatClient chatclient = OperationContext.Current.GetCallbackChannel<IWSChatClient>;
    ChatMessage text = receivedMessage.GetBody<ChatMessage>;
     (!m_NameList.Contains(text.To))
    {
      //保存数据到数据库
      ChatBLL bll = ChatBLL;
      bll.Add(text);
      ;
    }   
     (!chatClients.ContainsValue(chatclient))
    {
      ;
    }
    SendMessageToClient(text);
  }


  代码很少 ,如果用户没有登陆就把聊天信息保存到数据库否则直接发送到用户客户端去

  7:用户退出聊天室:

  }
  /// <summary>
  /// 退出聊天室
  /// </summary>
  /// <param name="receivedMessage"></param>
  [OperationContract(IsOneWay = true)]
  public void Exit(Message receivedMessage)
  {
    IWSChatClient client = OperationContext.Current.GetCallbackChannel<IWSChatClient>;
    ChatMessage cm = receivedMessage.GetBody<ChatMessage>;
     (chatUsers.Contains(cm.From))
    {
      chatUsers.Remove(cm.From);
    }
     (chatClients.ContainsKey(cm.From))
    {
      chatClients.Remove(cm.From);
    }
  }


  代码就是直接删除了队列中用户

  公共:发送数据到客户端:

 private void SendMessageToClient(ChatMessage chatMessage)
  {
     (chatMessage.To != null && chatClients.ContainsKey(chatMessage.To))
    {
      IWSChatClient chatclient = chatClients[chatMessage.To];
      Message Message = Message.CreateMessage(MessageVersion.Soap11, "WindCloud/WSChatService/Receive", chatMessage);
      try
      {
        chatclient.Receive(Message);
      }
      catch
      {
         (chatUsers.Contains(chatMessage.To))
        {
          chatUsers.Remove(chatMessage.To);
        }
         (chatClients.ContainsKey(chatMessage.To))
        {
          chatClients.Remove(chatMessage.To);
        }
      }
    }
  }


  如果发送时候发生异常就从队列删除

  8:ServerHost代码这个从MSDN上抄过来:

public ChatHostFactory : ServiceHostFactoryBase
{
  public override ServiceHostBase CreateServiceHost( constructorString, Uri baseAddresses)
  {
     ChatServiceHost(baseAddresses);
  }
}
ChatServiceHost : ServiceHost
{
  public ChatServiceHost(params .Uri addresses)
  {
    base.InitializeDescription(typeof(WSChatService), UriSchemeKeyedCollection(addresses));
  }
  protected override void InitializeRuntime
  {
    // Define the binding and time-outs.
    PollingDuplexBindingElement pdbe = PollingDuplexBindingElement
    {
      ServerPollTimeout = TimeSpan.FromSeconds(10),
      InactivityTimeout = TimeSpan.FromMinutes(1)
    };
    // Add an endpo for the given service contract.
    this.AddServiceEndpo(
      typeof(WSChatService),
       CustomBinding(
        pdbe,
         TextMessageEncodingBindingElement(
          MessageVersion.Soap11,
          .Text.Encoding.UTF8),
         HttpTransportBindingElement),
        "");
    base.InitializeRuntime;
  }
}




  9:svc文件代码:

<%@ServiceHost language=c# Debug="true" Factory="ChatHostFactory" %>

  这个也是从MSDN上抄写过来

  读写数据库代码其实可以完全注释掉这个只是为了有个保存功能整个代码还有不完善地方但是基本可以实现Duplex WCF从服务器向客户端推数据功能保证数据实时这也是长久也来我想了解服务器和客户端实时通信问题个解决办法



Tags:  silverlight.2.0 silverlight是什么 silverlight silverlightwcf

延伸阅读

最新评论

发表评论