WCF NetTcp независимая связь по дуплексному каналу
Я хочу создать дуплексный сервис 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);
}
}
1 ответ
Вы правы, что вам нужно использовать соединение, установленное клиентом. Для этого вам нужно выполнить несколько шагов:
- Убедитесь, что у вас есть
PerSession
(или жеSingleton
) контекстный режим экземпляра для вашего сервиса.PerCall
один не позволит вам поддерживать постоянную связь между клиентом и сервером. - Убедиться, что
ReceiveTimeout
на твоей привязке достаточно долго. Он должен быть длиннее периода между клиентскими запросами, чтобы незанятое соединение не прерывалось инфраструктурой WCF. - В вашем классе обслуживания вы должны помнить канал обратного вызова. Это должно быть сделано в методе, который вызывается клиентом. Итак, результат
OperationContext.Current.GetCallbackChannel<IStatusServiceCallBack>()
должны быть сохранены в частном полеStatusService
когда ты вSendNotification
метод. Если ваш сервис имеетPerSession
режим экземпляра, тогда у каждого класса обслуживания будет ровно один клиент. В случаеSingleton
Сервис, вам нужен набор обратных вызовов. - Можно возвращать значение для метода обратного вызова, но для вызова необходим объект канала обратного вызова (сохраненный на шаге 3).
- Если вы хотите вызвать метод обратного вызова на всех клиентах, вы должны хранить все обратные вызовы клиентов в статическом поле
StatusService
а затем вызвать метод для всех из них. - Если вы хотите вызывать метод обратного вызова только для определенного клиента, то вам нужен способ различать клиентов (ID, имя и т. Д.) И сохранять ссылки на каналы обратного вызова в словаре. Если ваш сервис имеет
PerSession
В режиме контекста экземпляра вы не можете напрямую получить доступ к объекту службы, поэтому все же рекомендуется как-то различать клиентов и обращаться к ним через статическое поле или что-то еще. Вы также можете внедрить свою собственную фабрику для создания сервисных объектов и затем иметь к ним доступ (при условии, что фабрика также где-то регистрирует эти объекты).
Помните, что если клиент отключается, он не делает канал обратного вызова недействительным немедленно. Вы обнаружите это только при вызове метода обратного вызова - исключение будет возвращено.