gpt4 book ai didi

c# - 具有来自后台线程的回调的 WCF 服务?

转载 作者:太空狗 更新时间:2023-10-29 19:42:00 25 4
gpt4 key购买 nike

这是我的情况。我编写了一个 WCF 服务,它调用我们供应商的代码库之一来执行操作,例如登录、注销等。此操作的要求是我们有一个后台线程来接收作为该操作结果的事件。例如,登录操作在主线程上发送。然后,作为登录的结果从供应商服务接收回几个事件。可以接收到 1 个、2 个或多个事件。在计时器上运行的后台线程接收这些事件并在 wcf 服务中触发一个事件以通知新事件已到达。

我已经在 Duplex 模式下实现了 WCF 服务,并计划使用回调来通知 UI 事件已经到达。这是我的问题:如何将新事件从后台线程发送到正在执行服务的线程?

现在,当我调用 OperationContext.Current.GetCallbackChannel<IMyCallback>() ,OperationContext 为空。是否有解决此问题的标准模式?

我在 ServiceContract 上使用 PerSession 作为我的 SessionMode。

更新:我想我可以通过演示我如何从供应商代码接收事件来使我的确切场景更加清晰。我的库接收每个事件,确定该事件是什么,并针对该特定事件触发一个事件。

我有另一个项目,它是一个专门用于连接到供应商服务的类库。我将发布该服务的整个实现以提供更清晰的图片:

    [ServiceBehavior(
InstanceContextMode = InstanceContextMode.PerSession
)]
public class VendorServer:IVendorServer
{
private IVendorService _vendorService; // This is the reference to my class library

public VendorServer()
{
_vendorServer = new VendorServer();
_vendorServer.AgentManager.AgentLoggedIn += AgentManager_AgentLoggedIn; // This is the eventhandler for the event which arrives from a background thread

}

public void Login(string userName, string password, string stationId)
{
_vendorService.Login(userName, password, stationId); // This is a direct call from the main thread to the vendor service to log in
}

private void AgentManager_AgentLoggedIn(object sender, EventArgs e)
{

var agentEvent = new AgentEvent
{
AgentEventType = AgentEventType.Login,
EventArgs = e
};
}
}

AgentEvent 对象包含回调作为其属性之一,我想我会像这样执行回调:

agentEvent.Callback = OperationContext.Current.GetCallbackChannel<ICallback>();

AgentEvent 是服务中定义的对象:

[DataContract]
public class AgentEvent
{
[DataMember]
public EventArgs EventArgs { get; set; }
[DataMember]
public AgentEventType AgentEventType { get; set; }
[DataMember]
public DateTime TimeStamp{ get; set; }
[DataMember]
public IVendorCallback Callback { get; set; }
}

IVendorCallback 看起来像这样:

    public interface IVendorCallback
{
[OperationContract(IsOneWay = true)]
void SendEvent(AgentEvent agentEvent);
}

回调在客户端上实现,并使用 AgentEvent 的 EventArgs 属性在 UI 上填充数据。我如何将 OperationContext.Current 实例从主线程传递到后台线程?

最佳答案

OperationContext.Current 仅在实际执行操作的线程上可用。如果您希望它对工作线程可用,那么您实际上需要将对回调 channel 的引用传递给该线程。

所以你的操作可能看起来有点像:

public class MyService : IMyService
{
public void Login()
{
var callback =
OperationContext.Current.GetCallbackChannel<ILoginCallback>();
ThreadPool.QueueUserWorkItem(s =>
{
var status = VendorLibrary.PerformLogin();
callback.ReportLoginStatus(status);
});
}
}

这是一种使用ThreadPool 和匿名方法变量捕获的直接方法。如果您想使用自由运行的线程执行此操作,则必须改用 ParameterizedThreadStart 并将 callback 作为参数传递。


具体示例更新:

似乎这里发生的事情是 IVendorService 使用一些事件驱动的回调模型。

由于您使用的是 InstanceContextMode.PerSession,实际上您可以将回调存储在服务类本身的私有(private)字段中,然后在您的事件处理程序中引用该字段。

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class VendorServer : IVendorServer
{
private IMyCallback callback;
private IVendorService vendorService;

public VendorServer()
{
callback = OperationContext.Current.GetCallbackChannel<IMyCallback>();
vendorService = new VendorService();
vendorService.AgentManager.AgentLoggedIn += AgentManager_AgentLoggedIn;
}

public void Login(string userName, string password, string stationId)
{
vendorService.Login(userName, password, stationId);
}

private void AgentManager_AgentLoggedIn(object sender, EventArgs e)
{
callback.ReportLoggedIn(...);
}
}

如果您稍后决定切换到不同的实例模式,那么这将不起作用,因为每个客户端都会有不同的回调。只要您将其保持在 session 模式,就应该没问题。

关于c# - 具有来自后台线程的回调的 WCF 服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2603135/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com