Reflection

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在本次实验中你将会看到几种不同的operation方式:request/reply、one-way和duplex callbacks。打开Operation文件夹下的Operation.sln解决方案。程序是一个交通灯的管理系统。
解决方案包含了三个项目:
TrafficLightClient项目包含了一个winform程序,用来表示单个交通灯:
 
TrafficController项目包含了一个winform程序,用来设置当前交通灯的状态:
 
你可以通过RadioButton来设置交通灯的状态,并通过点击Timer button来启动一个Timer来自动改变所有交通灯的状态。
最后,TraficLightService项目包含了一个服务,用来接受交通灯的新状态,并把这个状态通知所有正在运行的交通灯。

这个程序的架构如图所示:
 
交通灯连接到TrafficLightService来订阅交通灯状态。TrafficControllerForm会调用TrafficLightService并通知它新的交通灯的状态。TrafficLightService再把这个状态通知到所有的订阅者。
编译并运行程序,现在还没有很多事情会发生。目前唯一的contract是ITrafficLightStatus,TrafficControllerForm用它来设置状态:

enum LightColor
{
   Red,
   Yellow,
   Green
}


[ServiceContract]
interface ITrafficLightStatus
{
   [OperationContract]
   
void
 SetState(LightColor color);

   [OperationContract]
   LightColor GetState();
}


开发Service
TrafficLightService实现了ITrafficLightStatus接口:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class
 TrafficLightService : ITrafficLightStatus
{
   LightColor m_Color 
=
 LightColor.Red;

   
public void
 SetState(LightColor color)
   
{
      m_Color 
=
 color;
   }

   
public LightColor GetState()
   
{
      
return
 m_Color;
   }

}


TrafficLightService是一个单实例,也就是所有的client端都可以访问到它的状态。我们还需要添加一些功能让client端能够连接到service,并且让service回调它们通知状态。
在TrafficLightService.cs文件中加入ITrafficLightManager和ITrafficLightManagerCallback接口:

[ServiceContract(CallbackContract=typeof(ITrafficLightManagerCallback))]
interface
 ITrafficLightManager
{
    [OperationContract]
    LightColor Connect();

    [OperationContract]
    
void
 Disconnect();
}


interface ITrafficLightManagerCallback
{
    [OperationContract(IsOneWay
=true
)]
    
void
 OnStateChanged(LightColor newColor);
}


ITrafficLightManager只有一个任务,就是让client连接或者断开服务。并且告诉了WCF回调的接口。
TrafficLightService将会保存回调的引用,这样当交通灯状态改变时,它将会通知所有的client端这个新的状态。添加如下代码:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class
 TrafficLightService : ITrafficLightStatus, ITrafficLightManager
{
    LightColor m_Color 
=
 LightColor.Red;
    List
<ITrafficLightManagerCallback> m_Callback = new List<ITrafficLightManagerCallback>
();

    
public void
 SetState(LightColor color)
    
{
        m_Color 
=
 color;
        m_Callback.ForEach(
delegate
(ITrafficLightManagerCallback callback)
        
{
            callback.OnStateChanged(color);
        }
);
    }

    ……
    
public LightColor Connect()
    
{
        ITrafficLightManagerCallback callback 
= OperationContext.Current.GetCallbackChannel<ITrafficLightManagerCallback>
();
        m_Callback.Add(callback);
        
return
 m_Color;
    }


    
public void Disconnect()
    
{
        ITrafficLightManagerCallback callback 
= OperationContext.Current.GetCallbackChannel<ITrafficLightManagerCallback>
();
        m_Callback.Remove(callback);
    }

}

在app.config中为ITrafficLightManager添加endpoint:

<services>
 
<service name = "TrafficLightService">
  
<endpoint
     
address  = "net.tcp://localhost:8001/TrafficLightService"

     binding  
= "netTcpBinding"
     contract 
= "ITrafficLightStatus"
    
/>
  
<endpoint 
   
address="net.tcp://localhost:8002/TrafficLightService"
 
   binding
="netTcpBinding"
 
   contract
="ITrafficLightManager"
 
 
/>

 
</service>
</services>


编译程序,确保服务器端都正确。

开发client
在Proxy.cs文件中添加如下的定义:

[ServiceContract(CallbackContract = typeof(ITrafficLightManagerCallback))]
interface
 ITrafficLightManager
{
    [OperationContract]
    LightColor Connect();
    [OperationContract]
    
void
 Disconnect();
}


interface ITrafficLightManagerCallback
{
    [OperationContract(IsOneWay
=true
)]
    
void
 OnStateChanged(LightColor newColor);
}


class TrafficLightManagerClient : DuplexClientBase<ITrafficLightManager>, ITrafficLightManager
{
    
public
 TrafficLightManagerClient(InstanceContext inputInstance)
        : 
base
(inputInstance)
    
{ }


    
public LightColor Connect()
    
{
        
return
 Channel.Connect();
    }


    
public void Disconnect()
    
{
        Channel.Disconnect();
    }

}


注意到TrafficLightManagerClient是从DuplexClientBase<T>这个基类继承而来,主要的目的就是为了回调。
修改TrafficLightClient项目的app.config文件,加入endpoint:

  <client>
   
<endpoint 
    
address="net.tcp://localhost:8002/TrafficLightService"
 
    binding
="netTcpBinding"
 
    contract
="ITrafficLightManager" />

  
</client>

打开TrafficLight.cs文件,加入ITrafficLightManager的实现,添加一个代理类的实例;向服务端出入一个引用。

partial class TrafficLight : Form, ITrafficLightManagerCallback
{
    TrafficLightManagerClient m_TrafficManager;

    
public
 TrafficLight()
    
{
        InitializeComponent();
        InstanceContext instance 
= new InstanceContext(this
);
        m_TrafficManager 
= new
 TrafficLightManagerClient(instance);
        m_TrafficLightControl.State 
=
 m_TrafficManager.Connect();
    }

    
void OnClosing(object sender, FormClosingEventArgs e)
    
{
        m_TrafficManager.Disconnect();
        m_TrafficManager.Close();
    }


    
public void OnStateChanged(LightColor newColor)
    
{
        Thread.Sleep(
300
);
        m_TrafficLightControl.State 
=
 newColor;
    }

}

运行程序
解决方案已经配置为了多项目启动,直接按F5编译并运行程序。为了观察多个client端的运行情况,可以多启动几个client端:
 
我们可以观察到在OnStateChanged方法中会有延迟,几个client端不是同时在改变状态。解决这个问题我们可以将这个通知client的方法配置为one-way。在TrafficLightService.cs文件中将OnStateChanged方法配置为one-way:

interface ITrafficLightManagerCallback
{
    [OperationContract(IsOneWay
=true
)]
    
void
 OnStateChanged(LightColor newColor);
}


这下再运行一下程序,所有client端就会一起改变状态了。

posted on 2008-04-11 16:32  Reflection  阅读(701)  评论(2编辑  收藏  举报