Что происходит в WCF с методами с IsOneWay = true при завершении приложения - PullRequest
4 голосов
/ 06 декабря 2008

У меня есть клиентское приложение, которое время от времени уведомляет о своем прогрессе в обслуживании. Вызов метода для службы помечен IsOneWay = true, поскольку уведомление не требует никакого возвращаемого значения, и я не хочу откладывать.

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

Вопрос заключается в следующем: возвращает ли вызов метода oneway код вызывающего абонента после того, как он отправил сообщение? или оно ставит сообщение в очередь, а затем отправляется другим потоком?

Два процесса (клиент и служба) находятся на одной машине, и я заметил, что иногда (когда машина перегружена) служба не получает уведомление об ошибке. Я подозреваю, что второй вариант, который я упомянул, имеет место, но я не уверен.

Если я прав, как я могу убедиться, что уведомление отправлено, и сохранить метод в одном направлении?

Ответы [ 6 ]

8 голосов
/ 25 января 2012

Хороший вопрос. Прежде чем клиентское приложение вызывает метод, оно открывает канал. Канал используется для передачи всех данных. Существует два способа отправки: 1) надежный сеанс - когда ваши пакеты надежно удалены, а взломанные пакеты повторно отправлены, 2) упорядочение - когда запросы на службу вычисляются в порядке их передачи от клиента (а не как они доставляются) , Если у вас есть надежный заказанный сеанс, и у хоста службы возникают проблемы с данными после закрытия приложения, хост попытается запросить у клиента данные повторно, а после отсутствия ответа отклонит все ваши запросы. В другой ситуации (ненадежной) после открытия канала вы можете отправлять данные и уничтожать связь, односторонний метод вычислит ваш запрос, если не будет исключения.

Чтобы проверить некоторые возможности, связанные с проблемой обслуживания (однако не совсем так, ваша проблема с клиентом полезна), я создаю решение:

1) Библиотека проекта "WcfContracts" с одним файлом "IService1.cs":

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        void ThrowException();

        [OperationContract(IsOneWay=true)]
        void ThrowExceptionUseIsOneWay();
    }

2) Консольный проект "WcfConsoleHoster", который имеет ссылку на два "WcfContracts" и состоит из трех файлов:

a) Service1.cs, который является реализацией службы

public class Service1 : WcfContracts.IService1
{    
        public void ThrowException()
        {
            throw new Exception("Basic exception");
        }

        public void ThrowExceptionUseIsOneWay()
        {
            throw new Exception("Basic exception using IsOneWay=true");
        }
}

b) Program.cs, который имеет точку входа по умолчанию и просто запускает службу

static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(Service1));
        host.Open();
        Console.WriteLine("host 1 opened");
        Console.ReadKey();
    }

в) Сервис "App.config"

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="behavourHttpGet" name="WcfConsoleHoster.Service1">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/" />
          </baseAddresses>
        </host>
        <endpoint binding="wsHttpBinding" contract="WcfContracts.IService1" />        
        <endpoint address ="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behavourHttpGet">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

3) Консольный проект "WcfConsoleClient", который просто вызывает сервис

а) В "Program.cs"

Console.WriteLine("Wcf client. Press any key to start");
Console.ReadKey();
ChannelFactory<IService1> factory = new ChannelFactory<IService1>("Service1_Endpoint");
IService1 channel = factory.CreateChannel();
//Call service method
channel.ThrowException();

Console.WriteLine("Operation executed");
Console.ReadKey();

б) Клиент "App.config"

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="Service1_Endpoint"
        address="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/"
        binding="wsHttpBinding"
        contract="WcfContracts.IService1">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

1. Вызов исключения. Сначала мы вызываем двусторонний метод , который выдает исключение на хосте сервера. Затем это исключение возвращается к клиенту и канал поднимает его на стороне клиента, приложение уничтожается. Конечно, вы можете справиться с этим с помощью блока try () catch {}.

Давайте посмотрим так же с односторонним методом , вызвав channel.ThrowExceptionUseIsOneWay();. Исключение возникает в хосте службы, но на стороне клиента нет исключения, и мы получаем «Операция выполнена». Важно понимать, что канал будет недоступен для следующего использования.

Так что IsOneWay=true работает как положено - отправляет сообщение только одним способом. Вы не можете вернуть какой-либо объект из метода (ожидается void) и не можете использовать FaultContract или получить InvalidOperationException после запуска службы.

2. Thread.Sleep (). Следующий тест для массовой операции с Thread.Sleep(). IService1 расширен до

  [OperationContract]
  int ThreadSleep();

  [OperationContract(IsOneWay=true)]

и реализация в Service1.cs в ожидании 5 секунд

public int ThreadSleep()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
    return 1;
}

public void ThreadSleepUseIsOneWay()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
}

Теперь небольшая модификация для клиента для подсчета истекшего времени вызова

System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
//call methode
channel.ThreadSleep();
stopwatch.Stop();
Console.WriteLine(string.Format("Operation executed in {0} seconds", stopwatch.Elapsed.Seconds));
Console.ReadKey();

Вызов двустороннего метода ThreadSleep() приводит к результату «Операция выполнена за 7 секунд» (5 секунд для ожидания потока + 2 секунды для инициализации канала).

One way method с вызовом channel.ThreadSleepUseIsOneWay() имеет результат "0 секунд"! Там нет ожидания ответа службы!

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

2 голосов
/ 07 декабря 2008

Проверьте этот пост для получения подробной информации: http://kennyw.com/?p=130

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

1 голос
/ 22 марта 2013

У меня была похожая проблема (односторонний вызов ничего не делал или выбрасывал исключение). Я обнаружил, что десерилизатор, отвечающий за преобразование аргумента метода из xml обратно в объекты, создает исключение. Мой метод обслуживания никогда не достигался, и не возвращалось исключение, потому что это был односторонний вызов. Я не обнаружил его, пока временно не отключил «односторонний», поэтому мое исключение было передано обратно клиенту.

Надеюсь, это поможет кому-то еще в подобной ситуации.

1 голос
/ 31 января 2009

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

1 голос
/ 06 декабря 2008

Вы не можете «удостовериться, что уведомление отправлено» ... и «сохранить метод в одном направлении» Это противоречит тому, что означает "OneWay":

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

0 голосов
/ 04 января 2009

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

Я не уверен, что происходит на стороне клиента, если отбрасываются односторонние сообщения. Я предполагаю, что исключение / ошибка не генерируются, но я точно не знаю.

...