1.建立WCF Service,命名为ChatService
添加引用,
System.ServiceModel.dll
System.ServiceModel.PollingDuplex.dll
System.Runtime.Serialization.dll

2.定义接口IChatService.cs
    [ServiceContract(Namespace = "Silverlight",CallbackContract = typeof(IChatCallback),SessionMode = SessionMode.Required)]
    
public interface IChat
    
{

        [OperationContract(IsOneWay 
= true)]
        
void Order(Message receivedMessage);

        [OperationContract(IsOneWay 
= true)]
        
void JoinChat(Message receivedMessage);

        [OperationContract(IsOneWay 
= true)]
        
void SayChat(Message receivedMessage);
    }
相对应的callback接口
    [ServiceContract]
    
public interface IChatCallback
    
{
        [OperationContract(IsOneWay 
= true)]
        
void Receive(Message returnMessage);
    }

注意:在IChat中的属性 NameSpace一定要是SiliverLight,且在SessionMode中 要标明 SessionMode.Required 否则会出错

3.在Service文件中 定义服务
在文件ChatService.cs中添加以下代码:
static Dictionary<string, IChatCallback> chatClients = new Dictionary<string, IChatCallback>();
        
static List<string> m_NameList = new List<string>();
        
static int guestIndex = 1;

        
public void JoinChat(Message receivedMessage)
        
{
            IChatCallback chatclient;
            
bool userAdded = false;
            
string test;
            Message returnMessage;

            
string name = receivedMessage.GetBody<string>();

            chatclient 
= OperationContext.Current.GetCallbackChannel<IChatCallback>();

            test 
= "Service:JoiningPlease Wait";
            returnMessage 
= Message.CreateMessage(MessageVersion.Soap11,
                
"Silverlight/IChat/Receive", test);

            chatclient.Receive(returnMessage);

            
lock (syncObj)
            
{
                
if (name == "Guest")
                
{
                    name 
= "Guest" + guestIndex.ToString();
                    guestIndex 
= guestIndex + 1;
                }

                
if (!chatClients.ContainsKey(name) && name != "" && name != null)
                
{
                    test 
= "Service:Begin Add User To ChattersList";
                    returnMessage 
= Message.CreateMessage(MessageVersion.Soap11,
                        
"Silverlight/IChat/Receive", test);

                    chatclient.Receive(returnMessage);

                    
this.name = name;
                    m_NameList.Add(name);
                    chatClients.Add(name, chatclient);
                    userAdded 
= true;
                                       
                }

                
else
                
{
                    test 
= "Service:User:" + name + "Join fault.Already has this user or User name is NULL";

                    returnMessage 
= Message.CreateMessage(MessageVersion.Soap11,
                        
"Silverlight/IChat/Receive",test );

                    chatclient.Receive(returnMessage);

                    
return;
                }

            }


            
if (userAdded)
            
{
                
string text2 = "Service:User:" + name + " is already Joined";

                SendMessageToClient(text2);
            }

        }
这个方法是对应接口中的JoinChat,将用户添加到会话列表中。
其中,调用Receive接口将Message返回
然后,遍利用户字典,将信息发送给所有用户
        public void SayChat(Message receivedMessage)
        
{
            IChatCallback chatclient 
= OperationContext.Current.GetCallbackChannel<IChatCallback>();
            
string text = receivedMessage.GetBody<string>();

            
if(!chatClients.ContainsValue(chatclient))
            
{
                
return;
            }


            
//TODO: 用更好的方法实现
            for (int i = 0; i < m_NameList.Count; i++)
            
{
                IChatCallback clientInList 
= chatClients[m_NameList[i]];

                
if (clientInList.Equals(chatclient))
                
{
                    text 
= m_NameList[i] + " Says: " + text;
                    
break;
                }

            }


            SendMessageToClient(text);
        }


        
private void SendMessageToClient(string test)
        
{
            
//TODO: 用更好的方法实现
            for (int i = 0; i < m_NameList.Count; i++)
            
{
                IChatCallback chatclient 
= chatClients[m_NameList[i]];

                Message returnMessage 
= Message.CreateMessage(MessageVersion.Soap11,
                    
"Silverlight/IChat/Receive", test);

                chatclient.Receive(returnMessage);
            }

        }


4.添加宿主文件PollingDuplexServiceHostFactory.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;

namespace SLChat
{
    
public class PollingDuplexServiceHostFactory : ServiceHostFactoryBase
    
{
        
public override ServiceHostBase CreateServiceHost(string constructorString,
            Uri[] baseAddresses)
        
{
            
//return new PollingDuplexSimplexServiceHost(baseAddresses);

            PollingDuplexSimplexServiceHost serviceHost 
= new PollingDuplexSimplexServiceHost(baseAddresses);

            System.ServiceModel.Description.ServiceMetadataBehavior smb 
= serviceHost.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>();
            
if (smb != null)
            
{
                smb.HttpGetEnabled 
= true;
                
            }

            
else
            
{
                smb 
= new System.ServiceModel.Description.ServiceMetadataBehavior();
                smb.HttpGetEnabled 
= true;
                serviceHost.Description.Behaviors.Add(smb);
            }


            
return serviceHost;
        }

    }


    
class PollingDuplexSimplexServiceHost : ServiceHost
    
{
        
public PollingDuplexSimplexServiceHost(params System.Uri[] addresses)
        
{
            
base.InitializeDescription(typeof(ChatService), new UriSchemeKeyedCollection(addresses));
        }


        
protected override void InitializeRuntime()
        
{
            
// Define the binding and set time-outs.
            PollingDuplexBindingElement pdbe = new PollingDuplexBindingElement()
            
{
                PollTimeout 
= TimeSpan.FromSeconds(3),
                InactivityTimeout 
= TimeSpan.FromMinutes(1)
            }
;

            
// Add an endpoint for the given service contract.
            this.AddServiceEndpoint(
                
typeof(IChat),
                
new CustomBinding(
                    pdbe,
                    
new TextMessageEncodingBindingElement(
                    MessageVersion.Soap11,
                    System.Text.Encoding.UTF8),
                    
new HttpTransportBindingElement()),
                    
"");

            
base.InitializeRuntime();
        }

    }

}


5.一定不要忘记了 添加一个跨域访问的文件**(折磨我尽一天的问题。。。)
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  
<cross-domain-access>
    
<policy>
      
<allow-from http-request-headers="*">
        
<domain uri="*"/>
      
</allow-from>
      
<grant-to>
        
<resource path="/" include-subpaths="true"/>
      
</grant-to>
    
</policy>
  
</cross-domain-access>
</access-policy>
没有这个文件,在Windows自带的IIS中将发布不了,但是在VS2008的IIS是没有问题的

6.在VS的资源管理器(Solution Explore)右键点击ChatService.svc,点击View MarkUp
将原来的代码修改为:
<%@ServiceHost language=c# Debug="true" Service="SLChat.ChatService" Factory="SLChat.PollingDuplexServiceHostFactory"%>
使Service用我自己写的Host发布 而不用配置文件

这样服务端就完成了
 posted on 2008-07-11 17:56  monkey-猴子  阅读(2156)  评论(8编辑  收藏  举报