Objek komunikasi, System.ServiceModel.Channels.ServiceChannel, tidak dapat digunakan untuk komunikasi

156

Objek komunikasi, System.ServiceModel.Channels.ServiceChannel, tidak dapat digunakan untuk komunikasi karena berada dalam kondisi Faulted.

Tentang apa kesalahan ini, dan bagaimana cara saya menyelesaikannya?

Innova
sumber

Jawaban:

151

Anda mendapatkan kesalahan ini karena Anda membiarkan .NET pengecualian terjadi di sisi server Anda, dan Anda tidak menangkap dan menanganinya, dan tidak mengubahnya menjadi kesalahan SOAP.

Sekarang karena sisi server "dibom" keluar, runtime WCF telah "menyalahkan" saluran - mis. Tautan komunikasi antara klien dan server tidak dapat digunakan - lagi pula, sepertinya server Anda baru saja meledak, sehingga Anda tidak dapat berkomunikasi dengan itu lagi.

Jadi yang perlu Anda lakukan adalah:

  • selalu menangkap dan menangani kesalahan sisi server Anda - jangan biarkan .NET melakukan perjalanan dari server ke klien - selalu membungkusnya menjadi kesalahan SOAP yang dapat dioperasi. Periksa antarmuka WCF IErrorHandler dan implementasikan di sisi server

  • jika Anda akan mengirim pesan kedua ke saluran Anda dari klien, pastikan saluran tersebut tidak dalam kondisi bermasalah:

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

    Jika ya, yang dapat Anda lakukan adalah membuangnya dan membuat kembali proxy sisi klien lagi lalu coba lagi

marc_s
sumber
11
Tampaknya kesalahan yang sama dapat terjadi ketika masalah ada di sisi klien juga: misalnya, ketika kuota ukuran pesan untuk pesan masuk telah terlampaui.
svick
6
Bagaimana saya bisa membuat kembali klien?
Masoud
32

Untuk mencegah Server agar tidak jatuh dalam status Kesalahan, Anda harus memastikan bahwa tidak ada pengecualian yang ditangani. Jika WCF melihat Pengecualian yang tidak terduga, tidak ada lagi panggilan yang diterima - keselamatan terlebih dahulu.
Dua kemungkinan untuk menghindari perilaku ini:

  1. Gunakan FaultException (yang ini tidak terduga untuk WCF, jadi WCF tahu bahwa server masih memiliki status yang valid)
    alih-alih

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

    gunakan selalu

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

    mungkin Anda dapat mencoba .. raih seluruh blok dan lempar FaultException dalam semua kasus Pengecualian

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. Beri tahu WCF untuk menangani semua Pengecualian menggunakan Errorhandler. Ini dapat dilakukan dalam beberapa cara, saya memilih yang sederhana menggunakan Atribut:
    Yang harus kita lakukan lebih banyak, adalah menggunakan atribut [SvcErrorHandlerBehaviour]pada Implementasi Layanan yang diinginkan

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

Ini adalah contoh mudah, Anda dapat menyelam lebih dalam ke IErrorhandler dengan tidak menggunakan yang telanjang FaultException, tetapi FaultException<>dengan tipe yang memberikan info tambahan lihat IErrorHandler untuk contoh terperinci.

BerndK
sumber
10

Sebenarnya, jika tidak berhasil setelah mengikuti saran oleh marc_s , harap diingat bahwa elemen <security> dalam konfigurasi pengikatan server (atau ketiadaannya) di web.config di server dapat menyebabkan pengecualian ini. Misalnya server mengharapkan Messagekeamanan tingkat-dan klien dikonfigurasi untuk None(atau, jika server bukan bagian dari domain Direktori Aktif tetapi host klien jarak jauh adalah).

Tip: Dalam kasus seperti itu, aplikasi klien kemungkinan besar akan meminta denda layanan web ketika dijalankan langsung pada mesin server di bawah akun administratif dalam sesi RDP.

timmi4sa
sumber
2

Untuk mendiagnosis masalah ini, jalankan layanan di bawah Visual Studio debugger. Gunakan menu: Debug | Pengecualian dan tunjukkan bahwa Anda ingin memecah ketika Pengecualian dilemparkan.

Pengecualian asli yang dilemparkan akan memiliki pesan kesalahan yang jauh lebih baik daripada "..it dalam kondisi Faulted."

Misalnya saya mendapatkan pengecualian ini dari ServiceHost.Open (), tetapi ketika saya menangkap pengecualian asli pada saat itu dilemparkan, pesan kesalahannya adalah:

Layanan 'MyServiceName' tidak memiliki titik akhir aplikasi (non-infrastruktur). Ini mungkin karena tidak ada file konfigurasi yang ditemukan untuk aplikasi Anda, atau karena tidak ada elemen layanan yang cocok dengan nama layanan yang dapat ditemukan dalam file konfigurasi, atau karena tidak ada titik akhir yang didefinisikan dalam elemen layanan.

Memperbaiki kesalahan ejaan di App.config menyelesaikan masalah.

Dale Wilson
sumber
Dalam VS2015 pilih Debug → Pengaturan Pengecualian dan centang Pengecualian Runtime Bahasa Umum.
SharpC
1
Jadi mengapa tidak pengecualian asli diberikan sampai Anda menggunakan debugger Visual Studio?
Jez
2

Saya memiliki masalah yang sama ketika mencoba untuk mengkonsumsi titik akhir layanan net.tcp wcf dalam layanan http asmx.

Seperti yang saya lihat tidak ada yang menulis jawaban khusus MENGAPA masalah ini terjadi, tetapi hanya bagaimana ditangani dengan benar.

Saya telah bergumul dengannya beberapa hari berturut-turut dan akhirnya saya mengetahui dari mana masalahnya berasal dari kasus saya.

Awalnya saya berpikir bahwa ketika Anda membuat referensi ke layanan file config akan dikonfigurasi mengenai tag keamanan dengan cara yang sama seperti di sumbernya, tapi itu tidak terjadi dan saya harus mengatasinya secara manual. Dalam kasus saya, saya hanya punya

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

Kemudian saya melihat bahwa bagian keamanannya hilang dan seharusnya terlihat seperti ini

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

Masalah kedua dalam kasus saya adalah bahwa saya menggunakan transferMode="Streamed"layanan sumber WCF saya dan di klien saya tidak ada spesifik tentang hal itu, yang buruk, karena default transferModeadalah Buffereddan penting pada kedua sumber tempat dan klien harus dikonfigurasi dalam yang sama cara.

ppenchev
sumber
1

Saya punya masalah lain, yang saya pikir tidak disebutkan dalam jawaban lain.

Saya harus melayani titik akhir pada alamat dan port tcp yang sama. Di app.config, saya lupa menambahkan kedua titik akhir, sehingga layanan berjalan pada port yang benar, tetapi dengan antarmuka layanan yang salah.

Karsten
sumber
1

Jika Anda melihat pesan ini di Debug dari Visual Studio dan solusi berisi proyek WCF. Kemudian buka pengaturan proyek WCF ini -> buka tab "WCF Options" -> off "Mulai Host Layanan WCF ketika debugging ..." pilihan

Horev Ivan
sumber
Saya memiliki masalah yang sama dan terjebak pada masalah ini cukup lama. Mungkin bukan praktik yang baik untuk memiliki klien dan server pada solusi yang sama. Terima kasih!
yoosha
1

Bagi saya masalah ini disebabkan oleh file konfigurasi yang secara otomatis dibuat dengan mengimpor WSDL. Saya memperbarui ikatan dari basicHttpBinding ke customBinding. Menambahkan penanganan pengecualian tambahan tidak membantu menunjukkan hal ini.

Sebelum

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

Setelah

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

Dalam kasus saya alasannya adalah beberapa sertifikat salah yang tidak dapat dimuat. Saya mengetahuinya dari Event Viewer, di bawah Sistem:

Kesalahan fatal terjadi ketika mencoba mengakses kunci privat kredensial server TLS. Kode kesalahan yang dikembalikan dari modul kriptografi adalah 0x8009030D. Status kesalahan internal adalah 10001.

altumano
sumber
0

Kesalahan ini dapat dipicu oleh komputer Anda juga, dan bukan hanya pengecualian yang tidak ditangani. Jika server / komputer Anda memiliki waktu istirahatnya terlalu banyak, banyak layanan .NET web akan menolak permintaan Anda dengan kesalahan yang tidak tertangani. Ini ditangani dari sudut pandang mereka, tetapi tidak ditangani dari sudut pandang Anda. Periksa untuk memastikan waktu jam server penerima Anda sudah benar. Jika perlu diperbaiki, Anda harus mengatur ulang layanan Anda atau reboot sebelum saluran dibuka kembali.

Saya mengalami masalah ini di server di mana firewall memblokir pembaruan waktu Internet, dan server berhenti karena suatu alasan. Semua pihak ke-3. Layanan web NET rusak karena mereka menolak permintaan layanan web apa pun. Menggali Peraga Peristiwa membantu mengidentifikasi masalah, tetapi menyesuaikan jam dapat menyelesaikannya. Kesalahan ada di pihak kami meskipun kami menerima pesan kesalahan Negara Bagian untuk panggilan layanan web berikutnya.

HBlackorby
sumber
0

Server akan secara otomatis membatalkan koneksi yang tidak menerima pesan selama durasi yang sama dengan batas waktu penerimaan ( standarnya adalah 10 menit ). Ini adalah mitigasi DoS untuk mencegah klien memaksa server agar koneksi terbuka untuk waktu yang tidak terbatas.

Karena server membatalkan koneksi karena tidak digunakan, klien mendapatkan pengecualian ini.

Anda dapat mengontrol berapa lama server mengizinkan koneksi untuk idle sebelum membatalkannya dengan mengkonfigurasi batas waktu penerimaan pada pengikatan server. Kredit: TRVishwanath - MSFT

Vijay Rana
sumber
0

Saya tahu ini adalah posting yang lebih lama tetapi satu hal yang harus diperhatikan ketika Anda tidak dapat mengubah keamanan adalah memastikan bahwa nama pengguna dan kata sandi Anda telah ditetapkan.

Saya memiliki layanan dengan authenticationMode sebagai UserNameOverTransport, ketika nama pengguna dan kata sandi tidak ditetapkan untuk klien layanan saya akan mendapatkan kesalahan ini.

Joshua G
sumber
0

Bagi saya itu adalah masalah penyeimbang / url beban. Sebuah layanan web di belakang penyeimbang beban disebut layanan lain di belakang penyeimbang beban yang sama menggunakan url lengkap seperti: loadbalancer.mycompany.com. Saya mengubahnya untuk memintas penyeimbang beban saat memanggil layanan kedua dengan menggunakan localhost.mycompany.comsebagai gantinya.

Saya pikir ada semacam masalah referensi melingkar yang terjadi dengan penyeimbang beban.

goku_da_master
sumber
-2

Bukan solusi untuk masalah ini, tetapi jika Anda mengalami kesalahan di atas dengan Ektron eSync, bisa jadi database Anda telah kehabisan ruang disk.

Sunting: Sebenarnya ini bukan hanya masalah Ektron eSync saja. Ini bisa terjadi pada layanan apa pun yang meminta basis data lengkap.

Sunting: Kehabisan ruang disk, atau memblokir akses ke direktori yang Anda butuhkan akan menyebabkan masalah ini.

Jonathan Bick
sumber
Ini tidak memberikan jawaban untuk pertanyaan itu. Untuk mengkritik atau meminta klarifikasi dari penulis, tinggalkan komentar di bawah posting mereka - Anda selalu dapat mengomentari posting Anda sendiri, dan setelah Anda memiliki reputasi yang cukup, Anda akan dapat mengomentari setiap posting .
Dariusz
2
Saya menjawab pertanyaannya, "bagaimana cara saya menyelesaikannya?", Itu bukan salah saya, dia tidak pernah memberi kami detail apakah dia menggunakan Ektron atau tidak. Saya juga memerlukan 50 rep untuk mengomentari posnya.
Jonathan Bick