Каков надлежащий жизненный цикл прокси клиента службы WCF в Silverlight 3? - PullRequest
6 голосов
/ 10 ноября 2009

Я нахожу смешанные ответы на мой вопрос в Интернете. Для уточнения вопроса:

  1. Должен ли я создавать экземпляр прокси клиента службы один раз за асинхронный вызов или один раз за приложение Silverlight?
  2. Должен ли я явно закрывать прокси клиента службы (как я делаю в моем приложении ASP.NET MVC, синхронно вызывающем службы WCF)?

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

Ответы [ 3 ]

3 голосов
/ 20 декабря 2009

Я использую Silverlight с WCF начиная с V2 (сейчас работаю с V4), и вот что я нашел. В целом, это очень хорошо работает, чтобы открыть одного клиента и просто использовать этот один клиент для всех коммуникаций. И если вы не используете DuplexHttBinding, он также отлично работает, чтобы сделать прямо противоположное, открывать новое соединение каждый раз, а затем закрывать его, когда вы закончите. И из-за того, как Microsoft спроектировала клиента WCF в Silverlight, вы не увидите большой разницы в производительности между постоянным открытием одного клиента и созданием нового клиента с каждым запросом. (Но если вы создаете нового клиента с каждым запросом, убедитесь, что закрываете его также.)

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

Способ, которым я применил это в своем собственном коде, состоит в том, чтобы запустить все мои соединения через один статический класс DataConnectionManager, который выдает Assert, если я пытаюсь открыть второе соединение перед закрытием первого. Несколько фрагментов этого класса:

    private static int clientsOpen;
    public static int ClientsOpen
    {
        get
        {
            return clientsOpen;
        }
        set
        {
            clientsOpen = value;
            Debug.Assert(clientsOpen <= 1, "Bad things seem to happen when there's more than one open client.");
        }
    }

    public static RoomServiceClient GetRoomServiceClient()
    {
        ClientsCreated++;
        ClientsOpen++;
        Logger.LogDebugMessage("Clients created: {0}; Clients open: {1}", ClientsCreated, ClientsOpen);
        return new RoomServiceClient(GetDuplexHttpBinding(), GetDuplexHttpEndpoint());
    }

    public static void TryClientClose(RoomServiceClient client, bool waitForPendingCalls, Action<Exception> callback)
    {
        if (client != null && client.State != CommunicationState.Closed)
        {
            client.CloseCompleted += (sender, e) =>
            {
                ClientsClosed++;
                ClientsOpen--;
                Logger.LogDebugMessage("Clients closed: {0}; Clients open: {1}", ClientsClosed, ClientsOpen);
                if (e.Error != null)
                {
                    Logger.LogDebugMessage(e.Error.Message);
                    client.Abort();
                }
                closingIntentionally = false;
                if (callback != null)
                {
                    callback(e.Error);
                }
            };
            closingIntentionally = true;
            if (waitForPendingCalls)
            {
                WaitForPendingCalls(() => client.CloseAsync());
            }
            else
            {
                client.CloseAsync();
            }
        }
        else
        {
            if (callback != null)
            {
                callback(null);
            }
        }
    }

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

0 голосов
/ 15 февраля 2010

WCF имеет параметры конфигурации, которые сообщают ему, как долго он должен ждать возврата вызова, я думаю, что когда он не завершится в разрешенное время, AsyncClose закроет его. Поэтому вызовите client.AsyncClose ().

0 голосов
/ 11 ноября 2009

Вы должны открывать своего клиента за звонок и закрывать его сразу после. Если вы сомневаетесь, перейдите с помощью IE к файлу SVC и посмотрите на пример, который у них есть.

...