Đối tượng truyền thông, System.ServiceModel.Channels.ServiceChannel, không thể được sử dụng để liên lạc


156

Đối tượng truyền thông, System.ServiceModel.Channels.ServiceChannel, không thể được sử dụng để liên lạc vì nó ở trạng thái Lỗi.

Tất cả lỗi này là gì và tôi sẽ giải quyết nó như thế nào?

Câu trả lời:


151

Bạn gặp phải lỗi này vì bạn để một ngoại lệ .NET xảy ra ở phía máy chủ của mình và bạn cũng không bắt và xử lý nó, và cũng không chuyển đổi nó thành lỗi SOAP.

Bây giờ kể từ khi phía máy chủ "đánh bom", thời gian chạy WCF đã "lỗi" kênh - ví dụ: liên kết giao tiếp giữa máy khách và máy chủ không thể sử dụng được - sau tất cả, có vẻ như máy chủ của bạn vừa bị nổ, do đó bạn không thể giao tiếp với nó nữa

Vì vậy, những gì bạn cần làm là:

  • luôn luôn nắm bắt và xử lý các lỗi phía máy chủ của bạn - đừng để ngoại lệ .NET truyền từ máy chủ sang máy khách - luôn luôn khắc phục các lỗi đó thành các lỗi SOAP có thể tương tác. Kiểm tra giao diện WCF IErrorHandler và triển khai nó ở phía máy chủ

  • nếu bạn sắp gửi tin nhắn thứ hai lên kênh của mình từ máy khách, hãy đảm bảo kênh không ở trạng thái bị lỗi:

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

    Nếu có, tất cả những gì bạn có thể làm là loại bỏ nó và tạo lại proxy phía máy khách một lần nữa và sau đó thử lại


11
Có vẻ như lỗi tương tự cũng có thể xảy ra khi vấn đề nằm ở phía máy khách: ví dụ: khi hạn mức kích thước thư cho các tin nhắn đến đã bị vượt quá.
Svick

6
Làm thế nào tôi có thể tạo lại khách hàng?
Masoud

32

Để ngăn Máy chủ rơi vào trạng thái Lỗi, bạn phải đảm bảo rằng không có ngoại lệ chưa được xử lý nào được nêu ra. Nếu WCF thấy Ngoại lệ không mong muốn, sẽ không có thêm cuộc gọi nào được chấp nhận - trước tiên là an toàn.
Hai khả năng để tránh hành vi này:

  1. Sử dụng FaultException (điều này không bất ngờ đối với WCF, vì vậy WCF biết rằng máy chủ vẫn ở trạng thái hợp lệ)
    thay vì

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

    sử dụng luôn

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

    có lẽ bạn có thể thử..chọn toàn bộ khối và ném FaultException trong mọi trường hợp Ngoại lệ

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. Yêu cầu WCF xử lý tất cả các trường hợp ngoại lệ bằng Errorhandler. Điều này có thể được thực hiện theo nhiều cách, tôi đã chọn một cách đơn giản bằng cách sử dụng Thuộc tính:
    Tất cả chúng ta phải làm nhiều hơn, là sử dụng thuộc tính [SvcErrorHandlerBehaviour]trên Triển khai dịch vụ mong muốn

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

Đây là một ví dụ dễ hiểu, bạn có thể tìm hiểu sâu hơn về IErrorhandler bằng cách không sử dụng bản trần FaultException, nhưng FaultException<>với một loại cung cấp thông tin bổ sung, hãy xem IErrorHandler để biết ví dụ chi tiết.


10

Vì thực tế, nếu không thành công sau khi làm theo đề xuất của marc_s , xin lưu ý rằng phần tử <security> trong cấu hình ràng buộc máy chủ (hoặc thiếu) trong web.config trên máy chủ có thể gây ra ngoại lệ này. Chẳng hạn, máy chủ đang mong đợi Messagebảo mật -level và máy khách được cấu hình thành None(hoặc, nếu máy chủ không phải là một phần của miền Active Directory mà là máy chủ máy khách từ xa).

Mẹo: Trong những trường hợp như vậy, ứng dụng khách rất có thể sẽ gọi dịch vụ web tốt khi được thực thi trực tiếp trên máy chủ dưới tài khoản quản trị trong phiên RDP.


2

Để chẩn đoán sự cố này, hãy chạy dịch vụ theo trình gỡ lỗi Visual Studio. Sử dụng menu: Gỡ lỗi | Ngoại lệ và cho biết bạn muốn phá vỡ khi Ngoại lệ được ném.

Ngoại lệ ban đầu được ném sẽ có thông báo lỗi tốt hơn nhiều so với "..it đang ở trạng thái Lỗi."

Ví dụ: tôi đã nhận được ngoại lệ này từ Servicehost.Open (), nhưng khi tôi bắt gặp ngoại lệ ban đầu tại thời điểm nó bị ném, thông báo lỗi là:

Dịch vụ 'MyServiceName' không có điểm cuối ứng dụng (không phải cơ sở hạ tầng). Điều này có thể là do không tìm thấy tệp cấu hình cho ứng dụng của bạn hoặc vì không tìm thấy phần tử dịch vụ nào khớp với tên dịch vụ trong tệp cấu hình hoặc do không có điểm cuối nào được xác định trong phần tử dịch vụ.

Sửa lỗi chính tả trong App.config đã giải quyết vấn đề.


Trong VS2015, chọn Gỡ lỗi → Cài đặt ngoại lệ và đánh dấu Ngoại lệ thời gian chạy ngôn ngữ chung.
SharpC

1
Vậy tại sao không phải là ngoại lệ ban đầu được đưa ra cho đến khi bạn sử dụng trình gỡ lỗi Visual Studio?
Jez

2

Tôi gặp vấn đề tương tự trong khi cố gắng sử dụng điểm cuối dịch vụ wcf net.tcp trong dịch vụ http asmx.

Như tôi thấy không ai viết câu trả lời cụ thể TẠI SAO vấn đề này xảy ra, mà chỉ làm thế nào để xử lý đúng.

Tôi đã vật lộn với nó vài ngày liên tiếp và cuối cùng tôi đã tìm ra vấn đề đến từ đâu trong trường hợp của tôi.

Ban đầu tôi nghĩ rằng khi bạn tham chiếu đến một dịch vụ, tệp cấu hình sẽ được cấu hình liên quan đến thẻ bảo mật giống như trong nguồn, nhưng đó không phải là trường hợp và tôi nên xử lý thủ công. Trong trường hợp của tôi, tôi chỉ có

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

Sau đó tôi thấy rằng phần bảo mật bị thiếu và nó sẽ trông như thế này

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

Vấn đề thứ hai trong trường hợp của tôi là tôi đã sử dụng transferMode="Streamed"dịch vụ WCF nguồn của mình và trong máy khách, tôi không có gì cụ thể về nó, điều này rất tệ, bởi vì mặc định transferModeBufferedvà nó quan trọng đối với cả hai nguồn và máy khách được cấu hình giống nhau đường.


1

Tôi có một vấn đề khác, mà tôi không nghĩ đã được đề cập trong các câu trả lời khác.

Tôi phải phục vụ các điểm cuối trên cùng một địa chỉ tcp và cổng. Trong app.config, tôi đã quên thêm cả hai điểm cuối, vì vậy dịch vụ đang chạy trên đúng cổng, nhưng với giao diện dịch vụ sai.


1

Nếu bạn thấy thông báo này trong Debug từ Visual Studio và giải pháp chứa dự án WCF. Sau đó mở cài đặt dự án WCF này -> chuyển đến tab "Tùy chọn WCF" -> tắt tùy chọn "Khởi động máy chủ dịch vụ WCF khi gỡ lỗi ..."


Tôi đã có cùng một vấn đề và đã bị mắc kẹt trong vấn đề này trong một thời gian khá lâu. Có lẽ nó không phải là một thực hành tốt để có cả máy khách và máy chủ trên cùng một giải pháp. Cảm ơn bạn!
yoosha

1

Đối với tôi, vấn đề là do tập tin cấu hình tự động xuất hiện bằng cách nhập WSDL. Tôi đã cập nhật các liên kết đến từ basicHttpBinding sang customBinding. Thêm xử lý ngoại lệ bổ sung không giúp chỉ ra điều này.

Trước

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

Sau

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

0

Trong trường hợp của tôi, lý do là một số chứng chỉ sai không thể tải được. Tôi đã tìm hiểu về nó từ Trình xem sự kiện, trong Hệ thống:

Đã xảy ra lỗi nghiêm trọng khi cố gắng truy cập khóa riêng của thông tin máy chủ TLS. Mã lỗi được trả về từ mô-đun mật mã là 0x8009030D. Trạng thái lỗi nội bộ là 10001.


0

Lỗi này cũng có thể được kích hoạt bởi chính máy tính của bạn và không chỉ là một ngoại lệ chưa được xử lý. Nếu máy chủ / máy tính của bạn có thời gian tắt quá nhiều phút, nhiều dịch vụ web .NET sẽ từ chối yêu cầu của bạn với một lỗi chưa được xử lý. Nó được xử lý theo quan điểm của họ, nhưng không được xử lý theo quan điểm của bạn. Kiểm tra để đảm bảo thời gian đồng hồ của máy chủ nhận của bạn là chính xác. Nếu cần khắc phục, bạn sẽ phải đặt lại dịch vụ của mình hoặc khởi động lại trước khi kênh mở lại.

Tôi đã gặp sự cố này trên máy chủ nơi tường lửa chặn cập nhật thời gian Internet và máy chủ đã hết thời gian vì một số lý do. Tất cả các dịch vụ web .NET của bên thứ 3 đều gặp lỗi vì họ từ chối mọi yêu cầu dịch vụ web. Đi sâu vào Trình xem sự kiện đã giúp xác định vấn đề, nhưng điều chỉnh đồng hồ đã giải quyết nó. Lỗi là do lỗi của chúng tôi mặc dù chúng tôi đã nhận được thông báo lỗi Trạng thái bị lỗi cho các cuộc gọi dịch vụ web trong tương lai.


0

Máy chủ sẽ tự động hủy bỏ các kết nối mà không có tin nhắn nào được nhận trong khoảng thời gian bằng với thời gian chờ nhận ( mặc định là 10 phút ). Đây là một giảm thiểu DoS để ngăn khách hàng buộc máy chủ phải mở các kết nối trong một khoảng thời gian không xác định.

Vì máy chủ hủy kết nối vì nó không hoạt động, nên máy khách nhận được ngoại lệ này.

Bạn có thể kiểm soát thời gian máy chủ cho phép kết nối không hoạt động trước khi hủy bỏ nó bằng cách định cấu hình thời gian chờ nhận trên ràng buộc của máy chủ. Tín dụng: TRVishwanath - MSFT


0

Tôi biết đây là một bài viết cũ hơn nhưng một điều cần chú ý khi bạn không thể thay đổi bảo mật là đảm bảo rằng tên người dùng và mật khẩu của bạn đã được đặt.

Tôi đã có một dịch vụ với xác thựcMode là UserNameOverTransport, khi tên người dùng và mật khẩu không được đặt cho máy khách dịch vụ, tôi sẽ gặp lỗi này.


0

Đối với tôi đó là một vấn đề cân bằng tải / url. Một dịch vụ web đằng sau bộ cân bằng tải được gọi là dịch vụ khác đằng sau cùng bộ cân bằng tải bằng cách sử dụng url đầy đủ như : loadbalancer.mycompany.com. Tôi đã thay đổi nó để bỏ qua bộ cân bằng tải khi gọi dịch vụ thứ hai bằng cách sử dụng localhost.mycompany.comthay thế.

Tôi nghĩ rằng có một số loại vấn đề tham chiếu vòng tròn xảy ra với bộ cân bằng tải.


-2

Không phải là một giải pháp cho vấn đề này, nhưng nếu bạn gặp phải lỗi trên với Ektron eSync, thì có thể là cơ sở dữ liệu của bạn đã hết dung lượng đĩa.

Chỉnh sửa: Trên thực tế, đây không hoàn toàn là vấn đề của Ektron eSync. Điều này có thể xảy ra trên bất kỳ dịch vụ nào truy vấn cơ sở dữ liệu đầy đủ.

Chỉnh sửa: Hết dung lượng đĩa hoặc chặn quyền truy cập vào thư mục mà bạn cần sẽ gây ra sự cố này.


Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ - bạn luôn có thể nhận xét về bài đăng của riêng bạn và khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào .
Dariusz

2
Tôi đã trả lời câu hỏi của anh ấy "tôi sẽ giải quyết nó như thế nào?", Đó không phải là lỗi của tôi, anh ấy không bao giờ cho chúng tôi biết chi tiết về việc anh ấy có sử dụng Ektron hay không. Tôi cũng yêu cầu 50 đại diện để bình luận về bài viết của mình.
Jonathan Bick
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.