Я использую 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);
}
}
}
Раздражающая часть, конечно, в том, что если у вас есть только одно соединение, вам нужно перехватить его, когда оно неожиданно закрывается, и попытаться открыть его снова. И затем вам нужно повторно инициализировать все обратные вызовы, которые были обработаны вашими различными классами. Это на самом деле не так уж сложно, но раздражает убедиться, что все сделано правильно. И, конечно же, автоматическое тестирование этой части сложно, если не невозможно. , ,