服務器端回調有啥用呢?
比如:
向服務器上傳了一個文件,但是,爲了節約空間或出於其他目的,服務器要對剛上傳的文件進行處理(壓縮或者多媒體文件轉碼),這些操作無法馬上向客戶端回覆,而客戶端也不可能就停在這裏一直在等。我們希望,在客戶端上傳文件後馬上返回,而服務器對文件處理完成後再通知一下客戶端。
這樣就引出一個東東——回調,E文叫Call Back。我估計用E文表述可能更好理解,Call back就是相對於Call to而言的,即調用的方向與Call to相反。
在WCF中使用回調,只需要多定義一個接口即可,這個接口的方法和服務協定一樣,要附加OperationContractAttribute特性。
然後在定義服務協定時,在ServiceContractAttribute的CallbackContract中設置一個回調接口的Type。
在服務操作中,通過OperationContext的GetCallbackChannel方法取出回調協定的實例,調用回調的方法,就會在客戶端尋找回調接口的實現類並調用對應的成員。
下面我們做一個搖號程序進行說明
一、服務端
/// <summary>
/// 1、定義一個回調接口
/// </summary>
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void CallClient(int value);
}
/// <summary>
/// 2、定義服務協定
/// </summary>
[ServiceContract(Namespace="MyNamespace",
CallbackContract=typeof(ICallback),//標註回調協定
SessionMode=SessionMode.Required //要求會話
)]
public interface IService
{
/// <summary>
/// 會話從調用該操作開始
/// </summary>
[OperationContract(IsOneWay=true,IsInitiating=true,IsTerminating=false)]
void CallServerOperation();
/// <summary>
/// 調用該操作後,會話結束
/// </summary>
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
void End();
}
/// <summary>
/// 3、實現服務協定
/// </summary>
public class MyService : IService,IDisposable
{
private ICallback m_cb = null; //回調接口
private System.Threading.Timer m_timer = null; //計時器,定時幹活
private Random m_random = null;//隨機數
public void CallServerOperation()
{
m_cb = OperationContext.Current.GetCallbackChannel<ICallback>();
m_random = new Random();
//生成隨機數,並回調到客戶端;每3秒執行一次
m_timer = new System.Threading.Timer((obj) => m_cb.CallClient(m_random.Next()), null, 10, 3000);
}
public void End()
{
Console.WriteLine("會話結束");
}
public void Dispose()
{
m_timer.Dispose();
Console.WriteLine("{0}-服務實例已釋放.", DateTime.Now.ToLongTimeString());
}
}
//配置服務器
static void Main()
{
Console.Title = "WCF服務端";
//服務基地址
Uri baseUri = new Uri("http://localhost:3000/Service");
//聲明服務器主機
using (ServiceHost host = new ServiceHost(typeof(MyService), baseUri))
{
/*既支持會話傳輸速度又快的非TCP莫屬了,所以這裏我選擇NetTcpBinding;
* 這樣在默認行爲下,每啓動一個會話就創建一個服務實例,而當會話結束時就會釋放。
*/
//添加綁定和終結點
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(IService), binding, "net.tcp://localhost:1211/rr");
//添加服務描述
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
//啓動服務
try
{
host.Open();
Console.WriteLine("服務已啓動");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
//關閉服務
host.Close();
}
}
二、客戶端
在客戶端實現回調接口
/// <summary>
/// 實現回調接口
/// </summary>
public class MyCallback : WS.IServiceCallback
{
/// <summary>
/// 回調引發該事件
/// </summary>
public event EventHandler<int> ValueCallback;
/// <summary>
/// 因爲該方法是由服務器調用的
/// 如果希望在客戶端能及時作出響應,應當使用事件
/// </summary>
/// <param name="value">value</param>
public void CallClient(int value)
{
if (ValueCallback != null)
{
ValueCallback(this, value);
}
}
}
public partial class Form1 : Form
{
WS.ServiceClient m_sc;
readonly MyCallback m_mcallback;
public Form1()
{
InitializeComponent();
m_mcallback = new MyCallback();
m_mcallback.ValueCallback += mc_ValueCallback;
labNum.Text = "";
btnStop.Enabled = false;
}
void mc_ValueCallback(object sender, int e)
{
labNum.Text = e.ToString();
}
private void btnStart_Click(object sender, EventArgs e)
{
m_sc = new WS.ServiceClient(new System.ServiceModel.InstanceContext(m_mcallback));
m_sc.CallServerOperation();
btnStart.Enabled = false;
btnStop.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
m_sc.End();
btnStart.Enabled = true;
btnStop.Enabled = false;
}
}
效果如下: