服务器和客户端都使用.Net 4,
并且目前使用回调来进行异步 Web 服务调用。
但是服务器正在做的工作需要很长时间,我希望能够释放服务器上的请求线程(类似于客户端)。
是否可以使用 .Net Callbacks 在服务器上调用函数 A。
并且函数 B(在服务器上)会将答案返回给客户端回调函数?
我正在使用.NET Framework(不带 WCF)通过 HTTP 进行异步 Web 服务调用。
谢谢
拉斐尔
服务器和客户端都使用.Net 4,
并且目前使用回调来进行异步 Web 服务调用。
但是服务器正在做的工作需要很长时间,我希望能够释放服务器上的请求线程(类似于客户端)。
是否可以使用 .Net Callbacks 在服务器上调用函数 A。
并且函数 B(在服务器上)会将答案返回给客户端回调函数?
我正在使用.NET Framework(不带 WCF)通过 HTTP 进行异步 Web 服务调用。
谢谢
拉斐尔
在此示例代码中,客户端调用 ECF 服务器上的函数,服务器也调用客户端函数。
在以下示例中,您还可以找到事件订阅。
示例代码 SampleServiceClient :
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
using SampleServiceClient.SampleServiceReference;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;
namespace SampleServiceClient
{
/*WCF duplex use a SynchronizationContext by default, which means the callback will happen on UI threadm,
* so that you can update UI in your callback. But your client are calling your server in on the UI thread,
* so the callback will never be able to be delivered to your client. that's the orignal reason why it blocked.
*
Now if you use Synchronization=false, the callback will be delivered to you by a non-UI thread,
* that's why you can receive the callback now.
* After you receive the callback, you still want to update the UI in the UI thread,
* but the UI thread is still blocking now waiting for server response, so that's why it is blocking again, is it right?*/
[CallbackBehavior(UseSynchronizationContext = false)]
class SampleCallback : IService1Callback
{
frmClient frm;
public SampleCallback()
{
}
public SampleCallback(frmClient Form1)
{
frm = Form1;
}
public void ShowCallbackMessage(string message)
{
SetText("Callback message --> " + message);
}
public void OnPriceChanged(int value)
{
SetText("On Price Changed by client number : " + value.ToString());
}
private void SetText(String str)
{
SendOrPostCallback instance = new SendOrPostCallback(frm.AddItem);
frm.BeginInvoke(instance, str);
}
}
}
服务器端代码:
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
namespace SampleService
{
//No Service Contract Tag for Callback Inteface
interface ISampleCallback
{
[OperationContract(IsOneWay = true)]
void ShowCallbackMessage(string message);
[OperationContract(IsOneWay = true)]
void OnPriceChanged(int value);
}
//Name of Callback Contract on the WCF Service Contract which we want to expose to client
//You can assosiate only one CallBack Interface with a WCF Service Contract
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ISampleCallback))]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract (IsOneWay=true)]
void ChangePrice(int value);
//Code to Show Events Programming
[OperationContract]
bool SubscribeToPriceChangedEvent();
[OperationContract]
bool UnsubscribeFromPriceChangedEvent();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class Service1 : IService1
{
static List<ISampleCallback> clients = new List<ISampleCallback>();
private ISampleCallback callback=null;
internal ISampleCallback Callback
{
get { return callback; }
set { callback = value; }
}
public string GetData(int value)
{
//Invoke the callback operation in the client operation
callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
//All WCF channels implements the ICommunicationObject interface.
//If State is not opened then the service should not attempt to use callback.
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
Callback.ShowCallbackMessage("You are the client number " + value.ToString());
}
return string.Format("Callback message sent to client number " + value.ToString());
}
public void ChangePrice(int value)
{
raisePriceChangedEvent(value);
}
//Event Programming
public bool SubscribeToPriceChangedEvent()
{
try
{
Callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
if (!clients.Contains(Callback))
{
clients.Add(Callback);
}
return true;
}
catch (Exception)
{
return false;
}
}
public bool UnsubscribeFromPriceChangedEvent()
{
try
{
Callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
clients.Remove (Callback);
return true;
}
catch (Exception)
{
return false;
}
}
private void raisePriceChangedEvent(int value)
{
clients.ForEach(delegate(ISampleCallback oCallback)
{
if (((ICommunicationObject)oCallback).State == CommunicationState.Opened)
{
oCallback.OnPriceChanged(value);
}
else
{
clients.Remove(oCallback);
}
});
}
}
}