Каков надлежащий жизненный цикл прокси клиента службы WCF в Silverlight 3?

Я нахожу смешанные ответы на мой вопрос в Интернете. Чтобы уточнить вопрос:

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

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

3 ответа

Я использую 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);
            }
        }
    }

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

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

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

Другие вопросы по тегам