2011-03-28 12 views
15

Mamy usługę WCF, której używamy w aplikacji internetowej. Klient, którego używamy, został wygenerowany przy użyciu opcji Visual Studio "Dodaj odniesienie do usługi". Ponieważ jest to aplikacja internetowa, a ponieważ jej aplikacja może prowadzić do stosunkowo krótkich sesji, zdecydowaliśmy się utworzyć instancję klienta, gdy użytkownik się zaloguje i będzie go używać przez cały czas trwania sesji, a następnie unieszkodliwić go po zakończeniu sesji.Obsługa stałego klienta WCF wprowadzającego stan błędu

To doprowadza mnie do mojego pytania - staramy się wybrać najlepszy sposób postępowania z kanałem klienta wchodzącym w stan Zakłamany. Po poszukiwaniach wokół niektórych, mamy wymyślić to:

if(client.State = CommuncationState.Faulted) 
{ 
    client = new Client(); 
} 

try 
{ 
    client.SomeMethod(); 
} 
catch //specific exceptions left out for brevity 
{ 
    //logging or whatever we decide to do 
    throw; 
} 

To jednak nie działa ze względu na fakt, że, przynajmniej w naszym przypadku, nawet jeśli dana usługa jest w dół klienta pokaże Open, dopóki nie spróbujesz wykonać połączenia, używając go, a następnie wejdzie w stan Faulted.

To nas pozostawia do zrobienia czegoś innego. Inną opcją, którą wymyśliliśmy, było:

try 
{ 
    client.SomeMethod(); 
} 
catch 
{ 
    if(client.State == CommunicationState.Faulted) 
    { 
     //we know we're faulted, try it again 
     client = new Client(); 
     try 
     { 
      client.SomeMethod(); 
     } 
     catch 
     { 
      throw; 
     } 
    } 
    //handle other exceptions 
} 

Ale to pachnie. Oczywiście możemy tego uniknąć, używając nowego klienta i usuwając go dla każdego połączenia. Wydaje się to niepotrzebne, ale jeśli jest to właściwy sposób, to myślę, że to właśnie wybierzemy. Więc jaki jest najlepszy sposób, aby zręcznie obsługiwać ustalanie, czy klient jest w stanie błędu, a następnie coś z tym zrobić? Czy naprawdę powinniśmy po prostu otrzymywać nowego klienta dla każdego połączenia?

Jeszcze jedna rzecz, o której należy pamiętać - instancja klienta i wszystkie te sprawdzenia i obsługa odbywają się w klasie opakowania klienta. Jeśli zrobimy to w sposób, jaki sobie zaplanowaliśmy, jest to oczywiste dla samej aplikacji - wykonywanie połączeń i obsługa wyjątków od nich nie wymaga specjalnego kodu.

+0

Co powoduje, że klient wchodzi w stan błędu? Zawsze mogłem, aby usługa WCF zwracała normalnie awarię, a klient może kontynuować swoją działalność. Czy serwer nie odpowiada, czy coś? – Tridus

+0

W tym przypadku używamy członkostwa ASP.NET, a my natknęliśmy się na niego przez przekroczenie atrybutu "userIsOnlineTimeWindow". Oczywiście w takim przypadku wystarczy przekierowanie użytkownika na stronę logowania, ale staramy się upewnić, że jesteśmy przygotowani na każdą inną sytuację, w której moglibyśmy wejść w stan błędu. – Zannjaminderson

Odpowiedz

18

Aby odpowiedzieć na to pytanie, można obsługiwać Faulted event nieruchomości ChannelFactory takiego:

client.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted); 

To powinno pozwolić na wykonywanie niezależnie Rejestrowanie/porządkowe, które trzeba zrobić.

Jako ogólną rekomendację nie należy pozostawiać otwartego kanału na czas trwania sesji, więc upewnij się, że zamykasz kanał prawidłowo (przerywanie po wyjątku) po zakończeniu.

Również, jeśli to możliwe, należy rozważyć NIE korzystanie z podręcznika Visual Studio Add Service Reference lub przynajmniej wyczyszczenie generowanego kodu/konfiguracji.Polecam, jeśli chcesz użyć implementacji proxy, utwórz własne, korzystając z wersji ClientBase lub użyj implementacji ChannelFactory. Ponieważ wspominasz o klasie otoki, polecam użycie funkcji ChannelFactory i obsłużenie Faulted event dla potrzeb czyszczenia.

+0

Dzięki za odpowiedź. Widziałem wielu ludzi mówiących o otwieraniu i zamykaniu kanału klienta dla każdego połączenia i zastanawiam się, jakie są tego powody? – Zannjaminderson

+2

Powodem jest to, że możesz mieć tylko tyle równoczesnych połączeń i sesji równoległych do swojej usługi. Jeśli więc każda sesja w Twojej aplikacji internetowej ma otwartą sesję, szybko osiągniesz domyślny limit i musisz go zmienić, a wydajność ucierpi. Sprawdź to, aby uzyskać więcej informacji na temat optymalizacji tych (i innych) ustawień: http://msdn.microsoft.com/en-us/library/ee377061(v=bts.10).aspx – BrandonZeider

+0

Dzięki. Czytałem trochę więcej o ChannelFactory i wygląda na to, że będziemy zmierzać w tym kierunku. – Zannjaminderson

11

Spróbuj obsługi zdarzeń .Faulted na pełnomocnika klienta, np:

((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted); 

private void client_Faulted(object sender, EventArgs e) 
{ 
    client = new Client(); 
    ((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted); 
} 

To powinno spowodować natychmiastowe błędy kanału, co daje szansę, aby otworzyć ją ponownie.

Powinieneś również zawijać każde wywołanie do metody client w bloku try-catch, a być może nawet zawijać to w pętli while(), która ponawia próbę połączenia n razy, a następnie rejestruje niepowodzenie. EG:

bool succeeded = false; 
int triesLeft = 3; 
while (!succeeded && triesLeft > 0) 
{ 
    triesLeft--; 
    try 
    { 
     client.SomeMethod(); 
     succeeded = true; 
    } 
    catch (exception ex) 
    { 
     logger.Warn("Client call failed, retries left: " + triesLeft; 
    } 
} 
if (!succeeded) 
    logger.Error("Could not call web service"); 

W moim kodu mam poszedł tak daleko, aby korzystać z ManualResetEvent zablokować while() pętli aż do obsługi client_Faulted zdarzenie miało szansę ponownego tworzenia proxy client.

+1

Co powiesz na anulowanie subskrypcji zdarzenia "Faulted"? gdzie należy to zrobić? – itsho

Powiązane problemy