Об'єкт зв'язку System.ServiceModel.Channels.ServiceChannel не можна використовувати для зв'язку


156

Об'єкт зв'язку System.ServiceModel.Channels.ServiceChannel не може бути використаний для зв'язку, оскільки він знаходиться в стані Faulted.

Що це за помилка, і як би я вирішив її вирішити?

Відповіді:


151

Ви отримуєте цю помилку, тому що ви дозволяєте виключенню .NET статися на вашому сервері, і ви її не вловили та не обробили та не перетворили на помилку SOAP.

Тепер, оскільки серверна частина "бомбардувалась", час WCF "зірвав" канал - наприклад, зв'язок між клієнтом та сервером є непридатним - зрештою, схоже, що ваш сервер просто підірвався, тому ви не можете спілкуватися з це більше.

Отже, що вам потрібно зробити:

  • завжди ловіть і обробляйте помилки на стороні сервера - не дозволяйте .NET-виняткам подорожувати від сервера до клієнта - завжди обертайте їх у сумісні помилки SOAP. Перегляньте інтерфейс WCF IErrorHandler та застосуйте його на стороні сервера

  • якщо ви збираєтесь надіслати друге повідомлення на свій канал від клієнта, переконайтеся, що канал не знаходиться у несправному стані:

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

    Якщо це так, все, що ви можете зробити, це утилізувати його та знову створити проксі-сервер клієнта ще раз, а потім спробувати ще раз


11
Здається, така ж помилка може трапитися і тоді, коли проблема стоїть на стороні клієнта: наприклад, коли квота розміру повідомлень для вхідних повідомлень перевищена.
svick

6
Як я можу заново створити клієнта?
Масуд

32

Щоб запобігти падінню сервера в стані помилок, ви повинні переконатися, що жодне необроблене виключення не піднімається Якщо WCF бачить несподіваний виняток, більше не приймаються дзвінки - спочатку безпеку.
Дві можливості уникнути такої поведінки:

  1. Використовуйте FaultException (це не є несподіваним для WCF, тому WCF знає, що сервер все ще має дійсний стан)
    замість

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

    використовувати завжди

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

    можливо, ви можете спробувати .. зловити весь блок і кинути FaultException у всіх випадках винятку

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. Скажіть WCF обробляти всі винятки за допомогою Errorhandler. Це можна зробити декількома способами, я вибрав простий, використовуючи атрибут:
    Все, що нам потрібно зробити більше, - це використовувати атрибут [SvcErrorHandlerBehaviour]для потрібної реалізації служби

    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);
            }
        }
    }

Це простий приклад, ви можете зануритися глибше в IErrorhandler, не використовуючи голий FaultException, а FaultException<>тип, який надає додаткову інформацію, див. IErrorHandler для детального прикладу.


10

Насправді, якщо не вдалося виконати пропозиції marc_s , майте на увазі, що елемент <security> у конфігурації прив'язки сервера (або його відсутність) у web.config на сервері може спричинити цей виняток. Наприклад, сервер очікує Messageрівня безпеки і клієнт налаштований на None(або, якщо сервер не є частиною домену Active Directory, а хостом віддаленого клієнта).

Порада. У таких випадках клієнтська програма, швидше за все, вимагатиме штрафу веб-служби, коли виконується безпосередньо на серверній машині під адміністративним обліковим записом у сесії RDP.


2

Щоб діагностувати цю проблему, запустіть службу під налагоджувачем Visual Studio. Скористайтеся меню: Налагодження | Винятки та вкажіть, що ви хочете зламати, коли викинуто виняток.

Оригінальний виняток, викинутий, матиме набагато краще повідомлення про помилку, ніж ".. воно знаходиться у стані несправності".

Наприклад, я отримував цей виняток з ServiceHost.Open (), але коли я потрапив оригінальний виняток під час його викидання, повідомлення про помилку було:

Служба "MyServiceName" має нульову кінцеву точку застосування (неінфраструктура). Це може бути тому, що для вашої програми не знайдено файлу конфігурації або тому, що в файлі конфігурації не було знайдено жодного сервісного елемента, що відповідає імені служби, або тому, що в елементі служби не було визначено кінцевих точок.

Виправлення орфографічної помилки в App.config вирішило проблему.


У VS2015 виберіть «Налагодження» → «Налаштування винятку» та позначте «Винятки з загальної мови».
SharpC

1
Так чому не було дано оригінальне виняток, поки ви не використовували налагоджувач Visual Studio?
Джез

2

У мене була така ж проблема, коли я намагався споживати кінцеву точку служби net.tcp wcf у службі http asmx.

Як я бачив, ніхто не писав конкретної відповіді ЧОМУ виникає ця проблема, а лише як правильно впоратися.

Я боровся з цим кілька днів поспіль і, нарешті, з’ясував, звідки в моєму випадку проблема.

Спочатку я думав, що коли ви робите посилання на службу, конфігураційний файл буде налаштований щодо тегу безпеки так само, як і у джерелі, але це було не так, і я повинен подбати про це вручну. У моєму випадку я мав тільки

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

Пізніше я побачив, що частина безпеки відсутня, і це має виглядати приблизно так

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

Друга проблема в моєму випадку полягала в тому, що я використовував transferMode="Streamed"у моїй службі WCF-джерела, і у клієнта у мене нічого конкретного щодо цього не було, що було погано, тому що за замовчуванням transferModeє Bufferedі важливо, щоб і джерело, і клієнт були налаштовані в одній і тій же. шлях.


1

У мене виникла ще одна проблема, яку, на мою думку, не згадували в інших відповідях.

Я повинен обслуговувати кінцеві точки на одній і тій же адресі tcp та порту. У app.config я забув додати обидві кінцеві точки, тому служба працювала на правильному порті, але з неправильним інтерфейсом служби.


1

Якщо ви бачите це повідомлення у налагодженні від Visual Studio і рішення містить проект WCF. Потім відкрийте ці налаштування проекту WCF -> перейдіть на вкладку "Параметри WCF" -> вимкнено "Запустити хост служби WCF при налагодженні ..."


У мене була така ж проблема і застрягла в цьому питанні досить довго. Напевно, це не є хорошою практикою мати і клієнт, і сервер на одному і тому ж рішенні. Дякую!
йооша

1

Для мене проблема була викликана автоматично налаштованим файлом конфігурації імпортом WSDL. Я оновив прив'язку до basicHttpBinding до customBinding. Додавання додаткової обробки винятків не допомогло вказати на це.

До цього

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

Після

<customBinding>
        <binding name="ServiceName">
          <textMessageEncoding messageVersion="Soap12" />
          <httpsTransport />
        </binding>
      </customBinding>`

0

У моєму випадку причиною був неправильний сертифікат, який неможливо було завантажити. Я дізнався про це у засобі перегляду подій у системі:

Фактична помилка сталася під час спроби отримати доступ до приватного ключа облікового запису сервера TLS. Код помилки, повернутий з криптографічного модуля, становить 0x8009030D. Стан внутрішньої помилки 10001.


0

Цю помилку може спричинити і ваш власний комп'ютер, а не лише необроблений виняток. Якщо у вашого сервера / комп’ютера час роботи вичерпано на занадто багато хвилин, багато веб-сервісів .NET відхилять ваш запит із необробленою помилкою. Це обробляється з їхньої точки зору, але без обробки з вашого погляду. Переконайтесь, що час роботи вашого сервера приймає правильний. Якщо це потрібно виправити, вам доведеться скинути послугу або перезавантажитись, перш ніж канал знову відкриється.

У мене виникла ця проблема на сервері, де брандмауер блокував оновлення часу в Інтернеті, а сервер чомусь вийшов з роботи. Усі сторонні веб-сервіси .NET винили помилково, оскільки вони відхилили будь-який запит веб-служби. Копання у переглядачі подій допомогло визначити проблему, але налаштування годинника вирішило її. Помилка закінчилася, навіть якщо ми отримали повідомлення про помилку держави про помилку для майбутніх викликів веб-служб.


0

Сервер автоматично припиняє з'єднання, протягом яких не було отримано жодного повідомлення протягом тривалості, що дорівнює часу очікування прийому ( за замовчуванням - 10 хвилин ). Це зменшення DoS, щоб клієнти не змушували сервер відкривати з'єднання на невизначений час.

Оскільки сервер припиняє з'єднання, оскільки він не працює, клієнт отримує цей виняток.

Ви можете керувати тим, як довго сервер дозволяє з'єднанню вийти з режиму очікування, перш ніж перервати його, налаштувавши тайм-аут прийому на прив'язці сервера. Кредит: TRVishwanath - MSFT


0

Я знаю, що це старіша публікація, але одне, на що слід стежити, коли ви не можете змінити безпеку, - це переконатися, що ваше ім’я користувача та пароль встановлені.

У мене був сервіс з аутентифікацією Mode як UserNameOverTransport, коли ім'я користувача та пароль не були встановлені для клієнта служби, я отримав цю помилку.


0

Для мене це була проблема балансування навантаження / URL. Веб - сервіс за підсистему балансування навантаження називається інший служба за ту ж балансування навантаження , використовуючи повний URL , як: loadbalancer.mycompany.com. Я змінив його, щоб обійти балансир навантаження при виклику другої служби, використовуючи localhost.mycompany.comзамість цього.

Я думаю, що з балансиром навантаження виникала якась кругова довідкова проблема.


-2

Це не вирішення цієї проблеми, але якщо ви відчуваєте вищезгадану помилку з Ektron eSync, можливо, у вашій базі даних не вистачає місця на диску.

Редагувати: насправді це не зовсім проблема Ektron eSync. Це може статися на будь-якій службі, яка запитує повну базу даних.

Редагування: відсутність місця на диску або блокування доступу до потрібного каталогу спричинить цю проблему.


Це не дає відповіді на запитання. Щоб критикувати або вимагати роз'яснення у автора, залиште коментар під їх публікацією - ви завжди можете коментувати свої власні публікації, і як тільки у вас буде достатня репутація, ви зможете коментувати будь-яку публікацію .
Даріуш

2
Я відповів на його запитання "як би я вирішив це вирішити?", Я не моя вина, він ніколи не давав нам деталей щодо того, використовував він Ektron чи ні. Я також вимагаю 50 представників, щоб прокоментувати його повідомлення.
Джонатан Бік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.