Чтобы предотвратить закрытие соединения на стороне сервера, вы можете настроить метод Heartbeat () в контракте, который клиент может периодически вызывать. Это, однако, не идеально, потому что базовый сокет может упасть, и это ничего не делает для исправления этого.
Что касается вашего предложения 1) если на клиентской стороне вы наследуете от ClientBase, вы несколько застряли в том, что никакие указания на проблему не могут быть даны, пока вы не вызовете метод для маршрутизации в службу. Вам нужно будет обернуть вызов в попытку / перехват, а затем использовать некоторую логику переподключения:
public class MyClass : ClientBase<IContract>, IContract
{
public void ServiceMethod(String data) {
try {
base.Channel.ServiceMethod(data);
}
catch (CommunicationException ce) {
// Perform some reconnect logic here
base.Channel.ServiceMethod(data);
}
}
}
Ваш комментарий к предложению 2) является правильным, если между серверной стороной и клиентом существуют межсетевые экраны, они, скорее всего, не разрешат соединение
Edit:
Чтобы расширить мое предложение для 1), вам нужно будет создать новое соединение, когда вызов службы завершится неудачно с CommunicationException. Простейшим подходом было бы создать канал службы в конструкторе, а затем создать другой при сбое вызова:
class ServiceClient {
Service1Client mService; // Class generated by VS tool
public ServiceClient()
: base() {
mService = new Service1Client();
}
#region IService1 Members
public string GetData(int value) {
CommunicationState state = mService.State;
if (state == CommunicationState.Closed || state == CommunicationState.Faulted) {
mService = new Service1Client();
}
try {
// Note: The state checked above may not be accurate,
// hence the try...catch
return mService.GetData(value);
}
catch (CommunicationException) {
mService = new Service1Client(); // Reconnect logic
return mService.GetData(value); // If it fails again we are out of luck...
}
}
#endregion
}
Edit2:
В WCF сеанс обрабатывается клиентом. Если сеанс между клиентом и службой потерян, я не знаю способа восстановить этот сеанс, ни с клиента, ни со службы. Вы, к сожалению, застряли здесь.
Если служба хочет отправить с помощью обратного вызова с прерванным сеансом, проще говоря, она не может. Из-за того, как работают сети, сервис может не знать фактический адрес клиента. Эта и другие проблемы (например, брандмауэры) означают, что попытка восстановить соединение с клиентом из службы просто нецелесообразна. Единственный подход к службе - сохранить данные, которые он хотел отправить клиенту, и отправить их, когда служба обнаружит, что клиент повторно подключился.
Нет никакой гарантии, что клиент будет знать об удалении основного сокета, пока клиент не попытается отправить что-то через сокет, следовательно, попытка ... поймать. Воссоздание канала от клиента, как только он узнает о разорванном соединении, является единственным известным мне способом решения этой проблемы; что делает пример кода.
Идея сердцебиения - это способ активно бороться с нарушенной связью. Его эффективность зависит от ваших требований относительно того, насколько быстро вам нужно обнаружить разорванное соединение и сколько клиентов присутствует. Чем больше клиентов подключено, тем длиннее будет пульс, чтобы вы не загружали сеть в службу.
Edit3:
После некоторого дополнительного копания может быть способ сделать то, что вы хотите автоматически. Вы можете создать так называемый Reliable Session . Активация этого включает создание дополнительных записей в конфигурации:
<netTcpBinding>
<binding>
<reliableSession ordered="Boolean"
inactivityTimeout="TimeSpan"
enabled="Boolean" />
</binding>
</netTcpBinding>
Он также доступен для привязок, связанных с Http, см. Ссылку на документацию Microsoft по этой функции.