wcf 回调聊天

    技术2022-05-11  19

        这两天特意弄了一下Wcf 的回调.啃了一段时间的《wcf高级编程》还是略有收获,只是翻译的还是不尽人意.

        首先还是写服务契约,写在接口上。虽然可以写在类上,但这是个不好的方式

     

    [ServiceContract(SessionMode = SessionMode.Required,CallbackContract = typeof(IChatCallBack))] public interface IChat { [OperationContract] int JoinChatRoom(string strGuest);// [OperationContract(IsOneWay = true)] void LeaveChatRoom(string strGuest); [OperationContract(IsOneWay = true)] void SendMessage(string strSendName,string strReceiveName, string strInfo); [OperationContract] List<string> UserInfo()

    这是回调契约。这里可以不用再申明ServiceContract,因为上面用了CallBackContract 自然就申明了

    public interface IChatCallBack { [OperationContract(IsOneWay = true)] void NotifyGuestJoinedChatRoom(string guestName); [OperationContract(IsOneWay = true)] void NotifyGuestLeavedChatRoom(string guestName); /// <summary> /// 信息 /// </summary> /// <param name="strName">指定</param> [OperationContract(IsOneWay = true)] void NotifyMessage(string strName, string strInfo); }  

    写完了契约接口,自然要写实例了

    [ServiceBehavior( ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerCall)] public class Chat : IChat { private static Dictionary<string, IChatCallBack> _userinfo = new Dictionary<string, IChatCallBack>(); private static List<IChatCallBack> _callback = new List<IChatCallBack>(); private static int _PersonCount = 1; /// <summary> /// 加入聊天室 /// </summary> /// <param name="strGuest"></param> /// <returns></returns> public int JoinChatRoom(string strGuest) { IChatCallBack guest = OperationContext.Current.GetCallbackChannel<IChatCallBack>(); if (!_callback.Contains(guest)) { _callback.Add(guest); _userinfo.Add(strGuest, guest); } _callback.ForEach(delegate(IChatCallBack callback) { callback.NotifyGuestJoinedChatRoom(strGuest); }); return _PersonCount++; } /// <summary> /// 离开聊天室 /// </summary> /// <param name="strGuest"></param> public void LeaveChatRoom(string strGuest) { IChatCallBack guest = OperationContext.Current.GetCallbackChannel<IChatCallBack>(); if (!_callback.Contains(guest)) { _callback.Remove(guest); _userinfo.Remove(strGuest); } _callback.ForEach( delegate(IChatCallBack callback) { callback.NotifyGuestLeavedChatRoom(strGuest); } ); _PersonCount--; } /// <summary> /// 发送消息 /// </summary> public void SendMessage(string strSendName,string strReceiveName,string strInfo) { if (_userinfo.ContainsKey(strReceiveName)) { IChatCallBack callback = _userinfo[strReceiveName] as IChatCallBack; callback.NotifyMessage(strSendName, strInfo); } } public List<string> UserInfo() { List<string> count = new List<string>(); foreach(string list in _userinfo.Keys) { count.Add(list); } return count; }

    好了,现在得写一个宿主host,我用了一个控制台来做宿主

    Console.WriteLine("初始化服务..."); using (System.ServiceModel.ServiceHost host = new System.ServiceModel.ServiceHost(typeof(Chat))) { host.Open(); Console.WriteLine("服务已启动...."); Console.WriteLine(); Console.Read(); Console.WriteLine(""); }

      关键就在配置了,都说wcf好用,才发现配置是个很头痛的问题

    <system.serviceModel> <bindings> <netTcpBinding> <binding name="BindingBehaviorConfiguration"> <security mode="None"> <transport clientCredentialType="Windows" /> <message clientCredentialType="Windows" /> </security> </binding> </netTcpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="MetadataBehavior"> <serviceMetadata httpGetEnabled="true" httpGetUrl="http://192.168.168.44:8001/Chat/mex" /> <serviceTimeouts transactionTimeout="00:01:00"/> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="MetadataBehavior" name="Duplex.ServiceHost.Chat"> <endpoint address="service" binding="netTcpBinding" contract="Duplex.Service.IChat" name="TcpBinding" bindingConfiguration="BindingBehaviorConfiguration" /> <endpoint address="service" binding="wsDualHttpBinding" contract="Duplex.Service.IChat" name="HttpBinding" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" name="MexBinding"/> <host> <baseAddresses> <add baseAddress="net.tcp://192.168.168.44:8000/Chat/" /> <add baseAddress="http://192.168.168.44:8001/Chat/" /> </baseAddresses> </host> </service> </services> </system.serviceModel>

    请留意上面的Bindings 这段<bindings> <netTcpBinding> <binding name="BindingBehaviorConfiguration"> <security mode="None"> <transport clientCredentialType="Windows" /> <message clientCredentialType="Windows" /> </security> </binding> </netTcpBinding> </bindings>

    没有这段不能在跨机器访问服务,切记.

     

    服务写好了,那现在就是客户端了.首先写个代理类。

    public class ChatServiceClient:DuplexClientBase<Duplex.Service.IChat>,IChat { public ChatServiceClient(System.ServiceModel.InstanceContext callbackInstance) : base(callbackInstance) { } public ChatServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) : base(callbackInstance, endpointConfigurationName) { } public ChatServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress) : base(callbackInstance, endpointConfigurationName, remoteAddress) { } public ChatServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(callbackInstance, endpointConfigurationName, remoteAddress) { } public ChatServiceClient(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(callbackInstance, binding, remoteAddress) { } public int JoinChatRoom(string strGuest) { return base.Channel.JoinChatRoom(strGuest); } public void LeaveChatRoom(string strGuest) { base.Channel.LeaveChatRoom(strGuest); } public void SendMessage(string strSendName,string strReceiveName, string strInfo) { base.Channel.SendMessage(strSendName,strReceiveName, strInfo); } public List<string> UserInfo() { return base.Channel.UserInfo(); } }

     

    客户端用了winform写的

    [CallbackBehavior( ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)] public partial class Chat : Form,IChatCallBack { private SynchronizationContext _uiSyncContext = null; ChatServiceClient client = null; public Chat() { InitializeComponent(); _uiSyncContext= SynchronizationContext.Current; client = new ChatServiceClient(new InstanceContext(this), "TcpBinding"); } private void btnIn_Click(object sender, EventArgs e) { if (txtGuestName.Text.Trim() != "") { lblCount.Text = client.JoinChatRoom(txtGuestName.Text.Trim()).ToString(); btnIn.Enabled = false; } } #region IChatCallBack public void NotifyGuestJoinedChatRoom(string guestName) { SendOrPostCallback callback = delegate(object state) { WriteChatMessage(string.Format("{0} 加入了聊天室",guestName)); }; _uiSyncContext.Post(callback, guestName); // BindUserInfo(); } private void WriteChatMessage(string message) { string format = this.txtPartyLog.Text.Length > 0 ? "{0}/r/n{1} {2}" : "{0}{1} {2}"; this.txtPartyLog.Text = String.Format(format, this.txtPartyLog.Text, DateTime.Now.ToShortTimeString(), message); this.txtPartyLog.SelectionStart = this.txtPartyLog.Text.Length - 1; this.txtPartyLog.ScrollToCaret(); } public void NotifyGuestLeavedChatRoom(string guestName) { SendOrPostCallback callback = delegate(object state) { WriteChatMessage(string.Format("{0} 退出了聊天室", guestName)); }; _uiSyncContext.Post(callback, guestName); } public void NotifyMessage(string strName,string strInfo) { SendOrPostCallback callback = delegate(object state) { WriteChatMessage(string.Format("{0} 给你发送消息 {1}", strName,strInfo)); }; _uiSyncContext.Post(callback, strName); } #endregion private void Chat_Load(object sender, EventArgs e) { BindUserInfo(); } private void BindUserInfo() { List<string> list = client.UserInfo(); foreach (string name in list) { lstUser.Items.Add(name); } } private void btnOut_Click(object sender, EventArgs e) { if (txtGuestName.Text.Trim() != "") { client.LeaveChatRoom(txtGuestName.Text.Trim()); btnIn.Enabled = true; } } private void btnClear_Click(object sender, EventArgs e) { txtPartyLog.Text = ""; } private void btnSend_Click(object sender, EventArgs e) { client.SendMessage(txtGuestName.Text,lstUser.SelectedItem.ToString(), txtInfo.Text); } }

    不要认为这样就行了。客户端也要写相应的配置。

    <system.serviceModel> <bindings> <netTcpBinding> <binding name="BindingBehaviorConfiguration"> <security mode="None"> <transport clientCredentialType="Windows" /> <message clientCredentialType="Windows" /> </security> </binding> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://192.168.168.44:8000/Chat/service" binding="netTcpBinding" contract="Duplex.Service.IChat" name="TcpBinding" bindingConfiguration="BindingBehaviorConfiguration" /> <endpoint address="http://192.168.168.44:8001/Chat/service" binding="wsDualHttpBinding" contract="Duplex.Service.IChat" name="HttpBinding" /> </client> </system.serviceModel>

    基本上就搞定了。其实如果有个实例,其实是最好的说明,看了内容后。再看看不懂的地方查查资料。很容易理解。我写的很明了.

    下载 http://download.csdn.net/source/1623410

     


    最新回复(0)