Обнаружить отключение в WCF - PullRequest
0 голосов
/ 14 мая 2018

Мы создаем сервер WCF (.NET 4.5).Он будет использовать только транспорт net.pipe.

Когда клиент закрывает соединение PIPE, сервер получает необработанное исключение CommunicationException и завершается.

Q1.Как мне обработать CommunicationException, чтобы сервер не завершал работу и продолжал обслуживать других клиентов?

Q2.В обработчике, как я могу получить SessionId сеанса, который был прерван?Это нужно для очистки некоторых данных, относящихся к сеансу.

Заранее спасибо!

контракт

 [ServiceContract(CallbackContract = typeof(IContractCallback))]
 public interface IContractServer
{
[OperationContract(IsOneWay = true)]
void Connect(bool status);

[OperationContract(IsOneWay = false)]
void Disconnect(IContractServer _channelCallback);

[OperationContract(IsOneWay = true)]
void Play(bool status);
}

сервис

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service : IContractServer
{
public List<IContractCallback> _channeList = new List<IContractCallback>();

public void Connect(bool status)
{
    IContractCallback a = OperationContext.Current.GetCallbackChannel<IContractCallback>();
    int call = 0;
    foreach (var callBack in _channeList)
    {
        if (callBack == a)
        {
            call++;
        }
    }

    if (call == 0)
    {
        _channeList.Add(a);
        a.ConnectCallback(true);
    }
    else
    {
        a.ConnectCallback(false);
    }
}

public void Disconnect(IContractServer _channelCallback)
{
    foreach (var contractCallback in _channeList)
    {
        if (contractCallback == _channelCallback)
        {
            _channeList.Remove(contractCallback);
        }
    }
}

public void Play(bool status)
{
    foreach (var contractCallback in _channeList)
    {
        contractCallback.PlayCallback(status);
    }
}
}

клиент

using System.ComponentModel;
using System.ServiceModel;
using System.Windows;
using Host;

namespace VideoPlayer
{
 public partial class MainWindow : Window, IContractCallback
{
private IContractServer Proxy = null;
public MainWindow()
{
    InitializeComponent();
    InstanceContext context = new InstanceContext(this);
    DuplexChannelFactory<IContractServer> factory = new DuplexChannelFactory<IContractServer>(context, new NetNamedPipeBinding(), "net.pipe://localhost");
    Proxy = factory.CreateChannel();
    Proxy.Connect(true);
}

public void ConnectCallback(bool status)
{
    MessageBox.Show(status ? "connected" : "no connected");
}

public void PlayCallback(bool status)
{
    if (status)
    {
        MessageBox.Show("status true");
    }
    else
    {
        MessageBox.Show("status false");
    }
}


private void ButtonPlay(object sender, RoutedEventArgs e)
{
    Proxy.Play(true);
}


private void MainWindow_OnClosing(object sender, CancelEventArgs e)
{
    //хочу отправить сообщение о закрытии
    Proxy.Disconnect(Proxy);
}

1 Ответ

0 голосов
/ 14 мая 2018

Я сталкивался с этой проблемой раньше в своих дуплексных службах, когда событие, возникшее со стороны сервера, возникло исключение, если между клиентом и сервером не было живого канала, поэтому сервер перешел в состояние Fault и все последующие запросы не будут отвечать

По этой причине я пришел к такому выводу, чтобы проверить канал, и если он был жив, тогда позвольте вызвать методы возврата.

В сервисной части трюк будет похож на ↓

bool IsChannelAlive()
{
    Logging logging = new Logging(LogFile);
    try
    {
        if (((ICommunicationObject)_callbackChannel).State == CommunicationState.Opened)
        {
            logging.Log(LoggingMode.Prompt, "Channeld is still alive, can raise events...");
            return true;
        }
    }
    catch (Exception exp)
    {
        logging.Log(LoggingMode.Error, "IsChannelAlive()=> failed, EXP: {0}", exp);
    }
    logging.Log(LoggingMode.Warning, "Channeld is not alive so events won't raised...");
    return false;
}

и в одном из моих событий я использую это как:

void stran_OperationTimedOut(object sender, EventArgs e)
{ 
    if (IsChannelAlive())
        _callbackChannel.OnOperationTimedOut(); 
}

Но какое-то время я использую этот трюк, чтобы узнать, что закрытый канал что-то делает:

public ImportService()
{
    //Handle ContextClose to Audit all actions made in session
    OperationContext.Current.InstanceContext.Closed += delegate
    {
        //Here         
    };  
}

что не надежно.

Я все еще использую это IsAliveChannel() в своих услугах.

Надеюсь, что этот ответ разрешит вашу проблему или даст вам подсказку.

...