我想创建一个双工NetTcp服务。我不确定什么是最好的方法。 我有一个定期将其状态发送到服务器的客户端,我有一个必须定期发送独立于任何客户端请求的数据的服务器。 因为我想避免两个连接,并且对服务器上的客户端一无所知,所以我必须使用客户端打开的连接。 所以就像我说的,客户端会定期发送状态信息。 但是,我如何使用从客户端独立建立的连接通道向客户端发送数据。此外,从服务器发送到客户端的数据确实需要响应。
[ServiceContract(CallbackContract = typeof(IStatusServiceCallBack))]
public interface IStatusService
{
[OperationContract]
void SendStatus(int statusCode, string statusMessage);
}
public interface IStatusServiceCallBack
{
// I know IsOneWay=true cannot work, but how to return value????
[OperationContract(IsOneWay = true)]
int SendPayTransaction(PayTransaction payTransaction);
}
public class StatusService : IStatusService
{
public IStatusServiceCallBack Proxy
{
get
{
return OperationContext.Current.GetCallbackChannel
<IStatusServiceCallBack>();
}
}
public void SendNotification(int statusCode, string statusMessage)
{
Console.WriteLine($"nClient status : {(statusCode)} {statusMessage}");
}
// Is this possible???
public int SendPayTransaction(PayTransaction payTransaction){
return Proxy.SendPayTransaction(payTransaction)
}
}
class Program
{
static void Main(string[] args)
{
var svcHost = new ServiceHost(typeof(NotificationService));
svcHost.Open();
bool closeService = false;
do{
string command = Console.ReadLine();
if(command == "Send"){
// Is this possible???????
int result = svcHost.SendPayTransaction(new PaymentTransaction(){Amount = 5.50});
Console.WriteLine($"Result of payment : {result}");
} else if (command == "exit"){
closeService = true;
}
}while(!closeService);
}
}
你是对的,你需要使用客户端建立的连接。为此,您必须执行几个步骤:
- 确保服务具有
PerSession
(或Singleton
)实例上下文模式。PerCall
将不允许您在客户端和服务器之间保持永久连接。 - 确保装订上的
ReceiveTimeout
足够长。它应该长于客户端请求之间的时间段,以便 WCF 基础结构不会终止空闲连接。 - 在服务类中,您必须记住回调通道。这必须在客户端调用的方法中完成。因此,当您使用该方法时,
OperationContext.Current.GetCallbackChannel<IStatusServiceCallBack>()
的结果应保存到StatusService
SendNotification
的私人字段中。如果您的服务具有PerSession
实例模式,则每个服务类将只有一个客户端。如果是Singleton
服务,您需要一组回调。
回调 - 方法的返回值是可以的,但需要一个回调通道对象(保存在步骤 3 中)来调用它。
- 如果要在所有客户端上调用回调方法,则应将所有客户端回调保留在
StatusService
的静态字段中,然后在所有客户端上调用方法。 - 如果只想在特定客户端上调用回调方法,则需要一种方法来区分客户端(ID、名称等)并在字典中保留对回调通道的引用。如果您的服务具有实例上下文模式
PerSession
则无法直接访问服务对象,因此以某种方式区分客户端并通过静态字段或其他方式访问它们仍然是个好主意。您还可以注入自定义工厂以创建服务对象,然后有权访问它们(假设工厂也在某处注册这些对象)。
请注意,如果客户端断开连接,它不会立即使回调通道失效。只有当你调用回调方法时,你才会发现这一点 - 异常将被抛回。