Obiekt komunikacyjny System.ServiceModel.Channels.ServiceChannel nie może być używany do komunikacji

156

Obiekt komunikacyjny System.ServiceModel.Channels.ServiceChannel nie może być używany do komunikacji, ponieważ znajduje się w stanie Faulted.

O co chodzi w tym błędzie i jak mam go rozwiązać?

Innova
źródło

Odpowiedzi:

151

Otrzymujesz ten błąd, ponieważ pozwoliłeś, aby wyjątek .NET wystąpił po stronie serwera, a nie został on przechwycony i obsłużony, ani też nie przekształcił go w błąd protokołu SOAP.

Odkąd strona serwera została „zbombardowana”, środowisko wykonawcze WCF „zepsuło” kanał - np. Łącze komunikacyjne między klientem a serwerem jest bezużyteczne - w końcu wygląda na to, że serwer właśnie się rozpalił, więc nie można się z nim komunikować to już więcej.

Musisz więc:

  • zawsze wychwytuj i obsługuj błędy po stronie serwera - nie pozwól, aby wyjątki .NET podróżowały z serwera do klienta - zawsze pakuj je w interoperacyjne błędy SOAP. Sprawdź interfejs WCF IErrorHandler i zaimplementuj go po stronie serwera

  • jeśli masz zamiar wysłać drugą wiadomość na swój kanał od klienta, upewnij się, że kanał nie jest w stanie błędu:

    if(client.InnerChannel.State != System.ServiceModel.CommunicationState.Faulted)
    {
       // call service - everything's fine
    }
    else
    {
       // channel faulted - re-create your client and then try again
    }

    Jeśli tak, wszystko, co możesz zrobić, to zutylizować go i ponownie utworzyć serwer proxy po stronie klienta, a następnie spróbować ponownie

marc_s
źródło
11
Wygląda na to, że ten sam błąd może wystąpić, gdy problem występuje również po stronie klienta: na przykład, gdy przekroczony został limit rozmiaru wiadomości dla wiadomości przychodzących.
Svick
6
Jak mogę odtworzyć klienta?
Masoud
32

Aby zapobiec przechodzeniu serwera w stan błędu, należy upewnić się, że nie zostanie zgłoszony żaden nieobsługiwany wyjątek. Jeśli WCF widzi nieoczekiwany wyjątek, żadne więcej wywołań nie jest akceptowanych - najpierw bezpieczeństwo.
Dwie możliwości uniknięcia tego zachowania:

  1. Użyj FaultException (ten nie jest nieoczekiwany dla WCF, więc WCF wie, że serwer ma nadal prawidłowy stan)
    zamiast

    throw new Exception("Error xy in my function")  

    używaj zawsze

    throw new FaultException("Error xy in my function")  

    być może możesz spróbować ... złapać cały blok i zgłosić FaultException we wszystkich przypadkach Exception

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. Powiedz WCF, aby obsłużył wszystkie wyjątki przy użyciu Errorhandler. Można to zrobić na kilka sposobów, wybrałem prosty, używając atrybutu:
    wszystko, co musimy zrobić więcej, to użyć atrybutu [SvcErrorHandlerBehaviour]na żądanej implementacji usługi

    using System;
    using System.Collections.ObjectModel;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace MainService.Services
    {
        /// <summary>
        /// Provides FaultExceptions for all Methods Calls of a Service that fails with an Exception
        /// </summary>
        public class SvcErrorHandlerBehaviourAttribute : Attribute, IServiceBehavior
        {
            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            { } //implementation not needed
    
            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints,
                                             BindingParameterCollection bindingParameters)
            { } //implementation not needed
    
            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcherBase chanDispBase in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher channelDispatcher = chanDispBase as ChannelDispatcher;
                    if (channelDispatcher == null)
                        continue;
                    channelDispatcher.ErrorHandlers.Add(new SvcErrorHandler());
                }
            }
        }
    
        public class SvcErrorHandler: IErrorHandler
        {
            public bool HandleError(Exception error)
            {
                //You can log th message if you want.
                return true;
            }
    
            public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
            {
                if (error is FaultException)
                    return;
    
                FaultException faultException = new FaultException(error.Message);
                MessageFault messageFault = faultException.CreateMessageFault();
                msg = Message.CreateMessage(version, messageFault, faultException.Action);
            }
        }
    }

To jest prosty przykład, możesz zagłębić się w IErrorhandler, nie używając nagiego FaultException, ale FaultException<>z typem, który dostarcza dodatkowych informacji, zobacz IErrorHandler, aby uzyskać szczegółowy przykład.

BerndK
źródło
10

W rzeczywistości, jeśli nie powiedzie się po wykonaniu sugestii marc_s , należy pamiętać, że element <security> w konfiguracji powiązania serwera (lub jego brak) w web.config na serwerze może spowodować ten wyjątek. Na przykład serwer oczekuje Messagepoziomu bezpieczeństwa, a klient jest skonfigurowany na taki poziom None(lub, jeśli serwer nie jest częścią domeny Active Directory, ale zdalny host klienta jest).

Wskazówka: w takich przypadkach aplikacja kliencka najprawdopodobniej będzie poprawnie wywoływać usługę sieciową, gdy zostanie wykonana bezpośrednio na serwerze z kontem administratora w sesji RDP.

timmi4sa
źródło
2

Aby zdiagnozować ten problem, uruchom usługę w debugerze programu Visual Studio. Użyj menu: Debugowanie | Wyjątki i wskaż, że chcesz przerwać, gdy zostanie zgłoszony wyjątek.

Oryginalny zgłoszony wyjątek będzie miał znacznie lepszy komunikat o błędzie niż „.. jest w stanie błędu”.

Na przykład otrzymałem ten wyjątek z ServiceHost.Open (), ale kiedy złapałem oryginalny wyjątek w momencie, gdy został zgłoszony, komunikat o błędzie brzmiał:

Usługa „MyServiceName” ma zero punktów końcowych aplikacji (niezwiązanych z infrastrukturą). Może to być spowodowane tym, że nie znaleziono pliku konfiguracyjnego dla Twojej aplikacji, nie znaleziono elementu usługi pasującego do nazwy usługi w pliku konfiguracyjnym lub nie zdefiniowano żadnych punktów końcowych w elemencie usługi.

Naprawienie błędu pisowni w App.config rozwiązało problem.

Dale Wilson
źródło
W VS2015 wybierz Debuguj → Ustawienia wyjątków i zaznacz Wyjątki środowiska uruchomieniowego języka wspólnego.
SharpC,
1
Dlaczego więc nie podano oryginalnego wyjątku, dopóki nie użyłeś debugera programu Visual Studio?
Jez
2

Miałem ten sam problem podczas próby wykorzystania punktu końcowego usługi net.tcp wcf w usłudze http asmx.

Jak widziałem, nikt nie napisał konkretnej odpowiedzi DLACZEGO ten problem występuje, ale tylko jak należy go poprawnie rozwiązać.

Zmagałem się z tym kilka dni z rzędu i w końcu dowiedziałem się, skąd ten problem w moim przypadku.

Początkowo myślałem, że kiedy robisz odwołanie do usługi, plik konfiguracyjny zostanie skonfigurowany pod kątem tagu bezpieczeństwa w taki sam sposób, jak w źródle, ale tak nie było i powinienem zająć się tym ręcznie. W moim przypadku miałem tylko

<netTcpBinding>
    <binding name="NetTcpBinding_IAuthenticationLoggerService"
    </binding>
</netTcpBinding>`

Później zobaczyłem, że brakuje części zabezpieczającej i tak powinno wyglądać

<netTcpBinding>
    <binding name="NetTcpBinding_IAuthenticationLoggerService" transferMode="Buffered">
      <security mode="None">
        <transport clientCredentialType="None"/>
      </security>
    </binding>
  </netTcpBinding>

Drugim problemem w moim przypadku było to, że korzystałem transferMode="Streamed"z mojej źródłowej usługi WCF, aw kliencie nie miałem nic konkretnego na ten temat, co było złe, ponieważ wartość domyślna transferModeto Bufferedi ważne jest, aby zarówno źródło, jak i klient były skonfigurowane w tym samym sposób.

ppenchev
źródło
1

Miałem inny problem, o którym myślę, że nie został wspomniany w innych odpowiedziach.

Muszę obsługiwać punkty końcowe na tym samym adresie TCP i porcie. W pliku app.config zapomniałem dodać oba punkty końcowe, więc usługa działała na odpowiednim porcie, ale z niewłaściwym interfejsem usługi.

Karsten
źródło
1

Jeśli zobaczysz ten komunikat w debugowaniu z programu Visual Studio, a rozwiązanie zawiera projekt WCF. Następnie otwórz te ustawienia projektu WCF -> przejdź do karty „Opcje WCF” -> wyłącz opcję „Uruchom hosta usługi WCF podczas debugowania ...”

Horev Ivan
źródło
Miałem ten sam problem i utknąłem w tej sprawie na jakiś czas. Prawdopodobnie nie jest dobrą praktyką posiadanie zarówno klienta, jak i serwera na tym samym rozwiązaniu. Dziękuję Ci!
yoosha
1

U mnie problem był spowodowany przez plik konfiguracyjny automatycznie geneartowany przez import WSDL. Zaktualizowałem powiązanie z basicHttpBinding do customBinding. Dodanie dodatkowej obsługi wyjątków nie pomogło wskazać tego.

Przed

<basicHttpBinding>
            <binding name="ServiceName">
                <security mode="Transport" />
            </binding>
        </basicHttpBinding>`

Po

<customBinding>
        <binding name="ServiceName">
          <textMessageEncoding messageVersion="Soap12" />
          <httpsTransport />
        </binding>
      </customBinding>`
BGotIt
źródło
0

W moim przypadku przyczyną był zły certyfikat, którego nie można było załadować. Dowiedziałem się o tym z Podglądu zdarzeń, pod System:

Wystąpił błąd krytyczny podczas próby uzyskania dostępu do klucza prywatnego poświadczeń serwera TLS. Kod błędu zwrócony z modułu kryptograficznego to 0x8009030D. Wewnętrzny stan błędu to 10001.

altumano
źródło
0

Ten błąd może być również wywołany przez Twój komputer, a nie tylko przez nieobsługiwany wyjątek. Jeśli Twój serwer / komputer ma zbyt wiele minut przesunięcia zegara, wiele usług internetowych .NET odrzuci Twoje żądanie z nieobsługiwanym błędem. Jest obsługiwany z ich punktu widzenia, ale nie jest obsługiwany z Twojego punktu. Sprawdź, czy czas na serwerze odbierającym jest prawidłowy. Jeśli trzeba to naprawić, musisz zresetować usługę lub uruchomić ponownie przed ponownym otwarciem kanału.

Wystąpił ten problem na serwerze, na którym zapora sieciowa blokowała aktualizację czasu w Internecie, a serwer z jakiegoś powodu przestał działać. Wszystkie zewnętrzne usługi internetowe .NET uległy awarii, ponieważ odrzucały każde żądanie usługi sieci Web. Przeglądanie przeglądarki zdarzeń pomogło zidentyfikować problem, ale dostosowanie zegara rozwiązało go. Błąd był po naszej stronie, mimo że otrzymaliśmy komunikat o błędzie stanu błędu dla przyszłych wezwań serwisu internetowego.

HBlackorby
źródło
0

Serwer automatycznie przerwie połączenia, w których nie otrzymano żadnej wiadomości przez czas równy limitowi czasu odbioru ( domyślnie 10 minut ). Jest to zabezpieczenie przed atakiem DoS, aby zapobiec wymuszaniu przez klientów na serwerze otwierania połączeń przez nieokreślony czas.

Ponieważ serwer przerywa połączenie, ponieważ przeszedł w stan bezczynności, klient otrzymuje ten wyjątek.

Możesz kontrolować, jak długo serwer pozwala na bezczynne połączenie przed jego przerwaniem, konfigurując limit czasu odbioru w powiązaniu serwera. Źródło: TRVishwanath - MSFT

Vijay Rana
źródło
0

Wiem, że to starszy post, ale jedną rzeczą, na którą należy uważać, gdy nie możesz zmienić zabezpieczeń, jest upewnienie się, że Twoja nazwa użytkownika i hasło są ustawione.

Miałem usługę z authenticationMode jako UserNameOverTransport, gdy nazwa użytkownika i hasło nie były ustawione dla klienta usługi, otrzymywałbym ten błąd.

Joshua G
źródło
0

Dla mnie był to problem z równoważeniem obciążenia / adresem URL. Usługa WWW za równoważenia obciążenia nazywa inną usługę za tym samym równoważenia obciążenia przy użyciu pełnego adresu URL, takich jak: loadbalancer.mycompany.com. Zmieniłem to, aby ominąć moduł równoważenia obciążenia podczas wywoływania drugiej usługi, używając localhost.mycompany.comzamiast tego.

Myślę, że w module równoważenia obciążenia wystąpił jakiś problem z cyklicznymi odniesieniami.

goku_da_master
źródło
-2

Nie jest to rozwiązanie tego problemu, ale jeśli występuje powyższy błąd w Ektron eSync, może to oznaczać, że w bazie danych zabrakło miejsca na dysku.

Edycja: W rzeczywistości nie jest to wyłącznie problem dotyczący Ektron eSync. Może się to zdarzyć w przypadku każdej usługi wysyłającej zapytania do pełnej bazy danych.

Edycja: brak miejsca na dysku lub zablokowanie dostępu do katalogu, którego potrzebujesz, spowoduje ten problem.

Jonathan Bick
źródło
To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienie, zostaw komentarz pod jego postem - zawsze możesz komentować własne posty, a gdy zdobędziesz wystarczającą reputację , będziesz mógł skomentować każdy post .
Dariusz
2
Odpowiedziałem na jego pytanie „jak mam się zabrać do rozwiązania tego problemu?”, To nie moja wina, że ​​nigdy nie podał nam szczegółów, czy używa Ektron, czy nie. Potrzebuję również 50 przedstawicieli, aby skomentować jego post.
Jonathan Bick