WCF: Как я могу отправлять данные, изящно закрывая соединение? - PullRequest
0 голосов
/ 09 апреля 2010

У меня есть служба WCF, которая предлагает метод входа. Клиент должен вызывать этот метод (поскольку он является единственным IsInitiating = true). Этот метод должен возвращать строку, которая описывает успех вызова в любом случае. Если войти не удалось, соединение должно быть закрыто.

Проблема в сроках закрытия. Я хотел бы отправить возвращаемое значение, а затем немедленно закрыть соединение.

string Login (string name, string pass)
{
    if (name != pass) {
        OperationContext.Current.Channel.Close ();
        return "fail";
    }
    else {
        return "yay";
    }
}

MSDN утверждает, что вызов Close на канале

вызывает объект ICommunicationObject для изящный переход от открытого состояние в закрытое состояние. Закрыть метод позволяет любую незаконченную работу будет завершено до возвращения. За Например, закончить отправку любого буферизированного сообщения).

Это не сработало для меня (или мое понимание неверно), так как закрытие выполняется немедленно - WCF не ожидает завершения метода Login и возвращает строку, но закрывает соединение ранее.

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

В своем отчаянии я попробовал следующее, но вряд ли это серьезное решение.

new Thread (() => {
    Thread.Sleep (100);
    OperationContext.Current.Channel.Close ();
}).Start ();

Ответы [ 2 ]

6 голосов
/ 09 апреля 2010

Когда в документации говорится «изящно», это действительно говорит о том, что вы вызываете ICommunicationObject.Close со стороны клиента . На стороне service , если вы попытаетесь закрыть канал, пока клиент все еще ожидает ответа, у вас будет плохое время.

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

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

public string Login(string name, string pass)
{
    if (name != pass)
    {
        OperationContext.Current.OperationCompleted += LoginFailed;
        return "fail";
    }
    return "yay";
}

private void LoginFailed(object sender, EventArgs e)
{
    OperationContext.Current.Channel.Abort();
}

Это будет делать то, что я уверен, что вы хотите - отправить «сбой» обратно клиенту, очистить все, что нужно очистить, а затем отключить клиент, предотвращая любую дальнейшую активность в сеансе.

Между прочим, я не знаю, насколько это близко к реальному коду сервиса, но немного избыточно иметь метод «Логин» в сервисе, когда вы можете просто использовать встроенную в WCF систему учетных данных сервиса.

0 голосов
/ 09 апреля 2010

Почему вы хотите закрыть сервер соединений? Я понимаю, что вы хотите очистить любые ресурсы как можно скорее. Однако почему бы не справиться с этим, используя доступные параметры регулирования (режимы экземпляров и т. Д.) И параметры времени ожидания, которые предоставляет WCF?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...