服务器和客户端都使用.Net 4,
目前正在使用Callbacks进行异步Web服务调用。
但是服务器正在做的工作需要很长时间,我希望能够在服务器上释放请求线程(类似于客户端)。
是否可以使用.Net Callbacks来调用服务器上的功能A.
功能B(在服务器上)将返回客户端回调函数的答案吗?
我正在使用Asynchronous Web Service Calls over HTTP with the .NET Framework(没有WCF)。
由于
圣拉斐尔
答案 0 :(得分:0)
在此示例代码中,客户端在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);
}
});
}
}
}