36

障害状態に入ってはならない WCF サービスがあります。例外が発生した場合は、ログに記録し、サービスを中断することなく続行する必要があります。サービスには一方向の操作コントラクトがあり、MSMQ からメッセージを読み取ります。

私の問題は2つあります。

  1. サービスが例外/障害を飲み込んでいるように見えるため、デバッグできません。例外をログに記録または処理できるように、サービスに例外を公開させるにはどうすればよいですか?
  2. この例外が飲み込まれた後、サービスはフォルト状態に入ります。サービスが障害状態にならないようにするにはどうすればよいですか?
4

6 に答える 6

29

障害の処理方法に関する公式ドキュメントは次のとおりです。

メインページはChannel Model Overviewにあります

物事がどのように起こるかを示す素敵な状態図があります:

ここに画像の説明を入力

于 2011-05-10T08:43:13.307 に答える
21

すべてではないにしてもほとんどの例外は WCF トレース (「トレースの構成」) で確認でき、トレースは「サービス トレース ビューアー」で表示するのが最適です。

明らかに、これは実稼働環境で 1 日中実行する必要があるものではありませんが、とにかくトラブルシューティングに役立ちます。

それとは別に、使用する SessionMode によっては、oneways が真の「ファイア アンド フォーゲット」として実行されない場合があることに注意してください。サービスが SessionMode.Allowed または SessionMode.Required 用に構成されている場合、一方向操作はまったく一方向ではないかのように実行されます (これは、netTcpBinding で一方向を使用する場合に観察できます)。ただし、率直に言って、それによって取得できる例外の種類が変わるかどうか、または例外をいつ取得するかはわかりません。ただし、いずれにしても、リクエストをまったく送信できなかった場合は、例外が発生するはずです。私の知る限り、サーバー側で正常にエンキューされると、一方向は「終了」します。そのため、それまでは (WCF フレームワークに関連する) 例外の場所があります (シリアライゼーション/デシリアライゼーションが頭に浮かびます)。

次に、そのようなフレームワーク関連の例外は、上記のトレース/トレースビューアーを使用して最もよく確認できます (要求/応答フローで呼び出されたときに、IErrorHandler でさえ例外がすべて取得されるわけではありません)。

于 2008-11-25T06:54:29.903 に答える
12

例外はプロキシに障害を起こします。あなたはそれについて多くのことをすることはできません:例外を引き起こさないでください;-p

一方向性がまだ問題を引き起こしていることに少し驚いていますが、一般的な飲み込みは 3 つの側面があります。

  1. あなたは間違いを投げていますか?または例外?それは重要です(そして「障害」であるべきです)
  2. ハックとして、デバッグ例外メッセージを有効にできますが、オフにしてください!!!
  3. サービスオブジェクトを「使用」していますか? この正確なテーマについてブログを書いたところです...基本的に、「使用」は例外を飲み込むことができます。3 つのオプション:

    • 「使う」を使わない
    • プロキシをサブクラス化し、Dispose() をオーバーライドします
    • ブログのようにラップする
于 2008-11-24T22:41:14.550 に答える
10

通常、WCF サービスは ServiceHost でホストされます。WCF サービスが失敗した場合、唯一のオプションは、WCF サービスを強制終了して新しいサービスを開始することです。

ServiceHost には、WCF サービスが失敗したときにアクティブ化されるイベント トリガー "Faulted" があります。

ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Open();

障害の原因となる例外を取得することは可能ですが、もう少し作業が必要です。

public class ErrorHandler : IErrorHandler
{
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {

    }

    public bool HandleError(Exception error)
    {
        Console.WriteLine("exception");
        return false;
    }
}

public class ErrorServiceBehavior : IServiceBehavior
{
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {

    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        ErrorHandler handler = new ErrorHandler();
        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
        {
            dispatcher.ErrorHandlers.Add(handler);
        }
    }
}

ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Description.Behaviors.Add(new ErrorServiceBehavior());
host.Open();

クレジットhttp://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf

于 2009-12-02T15:12:01.140 に答える
7

2) について...

秘訣は、「using」を使用し、例外をスローしたプロキシで常に Abort() を呼び出す必要があることです。記事WCF Gotchaですべて説明されています。

サービス呼び出しをラップするその記事に触発されたサービス クラスを使用します。これは私のプロジェクトのサンプル コードです。

ServiceHelper<CodeListServiceClient, CodeListService.CodeListService>.Use(
    proxy => seasonCodeBindingSource.DataSource = proxy.GetSeasonCodes(brandID);
);

そしてこれが ServiceHelper のコードで、記事を少し修正したものです。これまでのところ、それは私たちに非常に役立っています。

using System;
using System.ServiceModel;

namespace Sportina.EnterpriseSystem.Client.Framework.Helpers
{
    public delegate void UseServiceDelegate<TServiceProxy>(TServiceProxy proxy);

    public static class ServiceHelper<TServiceClient, TServiceInterface> where TServiceClient : ClientBase<TServiceInterface>, new() where TServiceInterface : class
    {
        public static void Use(UseServiceDelegate<TServiceClient> codeBlock)
        {
            TServiceClient proxy = null;
            bool success = false;
            try
            {
                proxy = new TServiceClient();               
                codeBlock(proxy);
                proxy.Close();
                success = true;
            }
            catch (Exception ex)
            {
                Common.Logger.Log.Fatal("Service error: " + ex);                                
                throw;
            }
            finally
            {
                if (!success && proxy != null)
                    proxy.Abort();
            }
        }
    }
}
于 2008-11-25T07:12:15.313 に答える
7

ReceiveTimeout 例外の後、チャネルが障害状態のままになるという問題がありました。これにより、その後の接続でサービスが使用できなくなります。

サービスを障害状態から回復するための修正は、通信チャネルの Faulted イベントを処理することでした。

 channelFactory = new ChannelFactory<IService>(endpoint);
 channelFactory.Faulted += OnChannelFaulted;
 var channel = channelFactory.CreateChannel();

次に、OnChannelFaulted を定義します。

 void OnChannelFaulted(object sender, EventArgs e)
 {
     channelFactory.Abort();
 }

注: Web.config のバインディングを使用するのではなく、コードを介して WCF 構成を実行しています。

于 2009-09-25T22:58:27.310 に答える