ไม่สามารถใช้วัตถุการสื่อสาร 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
ฉันจะสร้างลูกค้าใหม่ได้อย่างไร
Masoud

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]ใน Service Implementation ที่ต้องการ

    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 ได้โดยไม่ต้องใช้ naked FaultExceptionแต่FaultException<>เป็นชนิดที่ให้ข้อมูลเพิ่มเติมดูIErrorHandlerสำหรับตัวอย่างโดยละเอียด


10

ตามจริงถ้าไม่สำเร็จหลังจากทำตามคำแนะนำโดยmarc_sโปรดทราบว่าองค์ประกอบ <security> ในการกำหนดค่าการเชื่อมโยงเซิร์ฟเวอร์ (หรือขาดดังกล่าว) ใน web.config บนเซิร์ฟเวอร์อาจทำให้เกิดข้อยกเว้นนี้ ตัวอย่างเช่นเซิร์ฟเวอร์คาดว่าจะมีการMessageรักษาความปลอดภัยระดับและไคลเอนต์มีการกำหนดค่าให้None(หรือหากเซิร์ฟเวอร์ไม่ได้เป็นส่วนหนึ่งของโดเมน Active Directory แต่โฮสต์ลูกค้าระยะไกลคือ)

เคล็ดลับ: ในกรณีเช่นนี้แอปไคลเอนต์มักจะเรียกใช้เว็บเซอร์วิสได้ดีเมื่อดำเนินการโดยตรงบนเครื่องเซิร์ฟเวอร์ภายใต้บัญชีผู้ดูแลระบบในเซสชัน RDP


2

เมื่อต้องการวินิจฉัยปัญหานี้ให้เรียกใช้บริการภายใต้ดีบักเกอร์ Visual Studio ใช้เมนู: Debug | ข้อยกเว้นและระบุว่าคุณต้องการแตกเมื่อมีการโยนข้อยกเว้น

ข้อผิดพลาดเดิมที่ส่งออกไปจะมีข้อความแสดงข้อผิดพลาดที่ดีกว่า "..it อยู่ในสถานะ Faulted"

ตัวอย่างเช่นฉันได้รับข้อยกเว้นนี้จาก ServiceHost.Open () แต่เมื่อฉันตรวจพบข้อยกเว้นดั้งเดิมในเวลาที่มีการโยนข้อผิดพลาดคือ:

บริการ 'MyServiceName' มีจุดสิ้นสุดแอปพลิเคชันที่ไม่มีโครงสร้างพื้นฐาน อาจเป็นเพราะไม่พบไฟล์การกำหนดค่าสำหรับแอปพลิเคชันของคุณหรือเนื่องจากไม่มีองค์ประกอบบริการที่ตรงกับชื่อบริการที่สามารถพบได้ในไฟล์การกำหนดค่าหรือเนื่องจากไม่มีการกำหนดจุดสิ้นสุดในองค์ประกอบบริการ

แก้ไขข้อผิดพลาดการสะกดคำใน App.config แก้ปัญหาได้


ใน VS2015 เลือก Debug →การตั้งค่าข้อยกเว้นและทำเครื่องหมายข้อยกเว้นรันไทม์ภาษาทั่วไป
SharpC

1
เหตุใดจึงไม่มีข้อยกเว้นดั้งเดิมให้จนกว่าคุณจะใช้ดีบักเกอร์ Visual Studio
Jez

2

ฉันมีปัญหาเดียวกันในขณะที่พยายามใช้จุดปลายบริการ net.tcp wcf ในบริการ http asmx

อย่างที่ฉันเห็นไม่มีใครเขียนคำตอบเฉพาะว่าทำไมปัญหานี้ถึงเกิดขึ้น แต่จะจัดการได้อย่างไรเท่านั้น

ฉันดิ้นรนกับมันหลายวันติดต่อกันและในที่สุดฉันก็พบว่าปัญหามาจากไหนในกรณีของฉัน

ตอนแรกฉันคิดว่าเมื่อคุณทำการอ้างอิงไปยังบริการไฟล์ config จะถูกกำหนดค่าเกี่ยวกับแท็กความปลอดภัยเช่นเดียวกับที่อยู่ในแหล่งที่มา แต่นั่นไม่ใช่กรณีและฉันควรดูแลด้วยตนเอง ในกรณีของฉันฉันมีเพียง

<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 และพอร์ตเดียวกัน ในแอปตั้งค่าฉันลืมเพิ่มจุดปลายทั้งสองดังนั้นบริการจึงทำงานบนพอร์ตที่ถูกต้อง แต่มีส่วนต่อประสานบริการที่ไม่ถูกต้อง


1

หากคุณเห็นข้อความนี้ใน Debug จาก Visual Studio และโซลูชันมีโครงการ WCF จากนั้นเปิดการตั้งค่าโครงการ WCF นี้ -> ไปที่แท็บ "ตัวเลือก WCF" -> ปิด "เริ่ม WCF Service Host เมื่อทำการดีบั๊ก ... "


ฉันมีปัญหาเดียวกันและติดอยู่กับปัญหานี้มาระยะหนึ่งแล้ว อาจไม่ใช่วิธีที่ดีที่จะมีทั้งไคลเอนต์และเซิร์ฟเวอร์ในโซลูชันเดียวกัน ขอบคุณ!
yoosha

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 ทั้งหมดเกิดข้อผิดพลาดเนื่องจากพวกเขาปฏิเสธคำขอบริการเว็บ การขุดลงใน Event Viewer ช่วยระบุปัญหา แต่การปรับนาฬิกาแก้ไขได้ ข้อผิดพลาดเกิดขึ้นในตอนท้ายแม้ว่าเราจะได้รับข้อความแสดงข้อผิดพลาด Faulted State สำหรับการเรียกใช้บริการเว็บในอนาคต


0

เซิร์ฟเวอร์จะยกเลิกการเชื่อมต่อโดยอัตโนมัติซึ่งไม่ได้รับข้อความใด ๆ ในช่วงเวลาเท่ากับระยะหมดเวลาที่ได้รับ ( ค่าเริ่มต้นคือ 10 นาที ) นี่คือการลดขนาด DoS เพื่อป้องกันไม่ให้ไคลเอ็นต์บังคับให้เซิร์ฟเวอร์เปิดการเชื่อมต่อเป็นระยะเวลาไม่ จำกัด

เนื่องจากเซิร์ฟเวอร์ยกเลิกการเชื่อมต่อเนื่องจากไม่ได้ใช้งานไคลเอ็นต์จะได้รับข้อยกเว้นนี้

คุณสามารถควบคุมระยะเวลาที่เซิร์ฟเวอร์อนุญาตให้การเชื่อมต่อไม่มีการใช้งานก่อนที่จะยกเลิกโดยการกำหนดค่าการหมดเวลารับของการเชื่อมโยงของเซิร์ฟเวอร์ เครดิต: TRVishwanath - MSFT


0

ฉันรู้ว่านี่เป็นโพสต์เก่า แต่มีสิ่งหนึ่งที่ต้องระวังเมื่อคุณไม่สามารถเปลี่ยนการรักษาความปลอดภัยได้เพื่อให้แน่ใจว่าตั้งชื่อผู้ใช้และรหัสผ่านของคุณแล้ว

ฉันมีบริการที่มี authenticationMode เป็น UserNameOverTransport เมื่อไม่ได้ตั้งชื่อผู้ใช้และรหัสผ่านสำหรับไคลเอ็นต์บริการฉันจะได้รับข้อผิดพลาดนี้


0

สำหรับฉันมันเป็นปัญหาตัวโหลดบาลานซ์ / url บริการเว็บเบื้องหลัง balancer โหลดเรียกว่าบริการอื่นที่อยู่เบื้องหลัง balancer โหลดเดียวกันโดยใช้ URL loadbalancer.mycompany.comแบบเต็มเช่น: ฉันเปลี่ยนเป็นบายพาสโหลดบาลานเซอร์เมื่อเรียกเซอร์วิสที่สองโดยใช้localhost.mycompany.comแทน

ฉันคิดว่ามีปัญหาการอ้างอิงแบบวงกลมเกิดขึ้นกับ load balancer


-2

ไม่ใช่วิธีการแก้ไขปัญหานี้ แต่ถ้าคุณพบข้อผิดพลาดข้างต้นกับ Ektron eSync อาจเป็นไปได้ว่าฐานข้อมูลของคุณมีพื้นที่ดิสก์ไม่เพียงพอ

แก้ไข: อันที่จริงนี่ไม่ใช่ปัญหาทั้งหมดของ Ektron eSync เท่านั้น สิ่งนี้อาจเกิดขึ้นกับบริการใด ๆ ที่สอบถามฐานข้อมูลแบบเต็ม

แก้ไข: พื้นที่ดิสก์ไม่เพียงพอหรือบล็อกการเข้าถึงไดเรกทอรีที่คุณต้องการจะทำให้เกิดปัญหานี้


สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม จะวิจารณ์หรือการร้องขอคำชี้แจงจากผู้เขียนแสดงความคิดเห็นด้านล่างโพสต์ของพวกเขา - คุณสามารถแสดงความคิดเห็นในโพสต์ของคุณเองและเมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด
Dariusz

2
ฉันตอบคำถามของเขาว่า "ฉันจะแก้ไขได้อย่างไร" ไม่ใช่ความผิดของฉันที่เขาไม่เคยให้รายละเอียดแก่เราว่าเขาใช้ Ektron หรือไม่ ฉันยังต้องการ 50 ตัวแทนเพื่อแสดงความคิดเห็นในโพสต์ของเขา
Jonathan Bick
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.