2

私は奇妙な問題に直面しました: 私が構築している WCF Web サービスはデバッグ モードで実行されますが、リリースでは実行されません。

文字列を返すだけで他に何もしない (ロギングも例外処理も何もしない) Web サービスに単純な Hello Web メソッドがあります。.svc ファイルを選択し、F5 をクリックしてデバッグを開始することにより、Visual Studio 内から WCFTestClient を実行します。WCFTestClient が開いたら、Hello Web メソッドをダブルクリックして呼び出します。デバッグモードでは正常に動作します。リリースモードでは、ほぼ瞬時に次のエラーが発生します。

Object reference not set to an instance of an object.

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at IVehicleRisk.Hello()
   at VehicleRiskClient.Hello()

(Web サービスは VehicleRisk.svc で、サービス コントラクトは IVehicleRisk です)。

アプリケーションにブレークポイントを追加すると、Hello Web メソッドを呼び出すと、Global.asax.cs の Application_BeginRequest メソッドが呼び出されていることがわかります (これは空のメソッドです)。例外がスローされたとき、VehicleRisk.svc.cs のブレークポイントは、コンストラクターでも Hello メソッドでもヒットしていません (Web メソッドが機能している場合、ブレークポイントはヒットしています)。

Visual Studio でプロジェクトのビルド プロパティを確認しました (ソリューション エクスプローラーでプロジェクトを右クリックし、[プロパティ] を選択して、[プロパティ] ウィンドウの [ビルド] タブを開きます)。デバッグ モードとリリース モードの唯一の違いは次のとおりです。

  1. DEBUG 定数を定義します。デバッグ モードではオンに設定し、リリース モードではオフに設定します。

  2. コードの最適化: デバッグ モードではオフに設定し、リリースではオンにします。

  3. Advanced > Output Debug Info: デバッグ モードでは full に設定し、リリースでは pdb-only に設定します。

リリース モードでビルド プロパティを変更して実験したところ、コードの最適化がオフに設定され、[詳細設定] > [デバッグ情報を出力] が完全に設定されている場合にのみ Web メソッドが機能することがわかりました。DEBUG 定数をオンまたはオフに設定しても違いはありません。

コードの最適化がオンになっているとき、またはデバッグ情報が pcb-only に設定されているときに、単純な Web メソッドが失敗する理由を知っている人はいますか?

4

3 に答える 3

2

コードを見なければ、何が問題なのかを判断するのは困難です。

機能するサンプル プロジェクトを再作成するために、次のサービス インターフェイスを使用して WCF サービス アプリケーションを作成しました。

using System.ServiceModel;

namespace HelloWCF
{
    [ServiceContract]
    public interface IHelloService
    {
        [OperationContract]
        string SayHello(string name);
    }
}

次に、このインターフェイスを次のクラスで実装しました。

namespace HelloWCF
{
    public class HelloService : IHelloService
    {
        public string SayHello(string name)
        {
            return string.Format("Hello, {0}", name);
        }
    }
}

また、次のサービス<system.servicemodel>構成を web.config のセクションに追加しました。

    <services>
        <service name="HelloWCF.HelloService" 
                 behaviorConfiguration="SimpleBehavior">
            <endpoint 
                 binding="basicHttpBinding" 
                 contract="HelloWCF.IHelloService" />
            <endpoint 
                 address="mex" 
                 binding="mexHttpBinding" 
                 contract="IMetadataExchange" />
        </service>
    </services>

また、サービスの動作に次の名前を付けました。

<behaviors>
    <serviceBehaviors>
        <behavior name="SimpleBehavior">
            <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
            <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
            <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
            <serviceDebug includeExceptionDetailInFaults="false"/>                    
        </behavior>
    </serviceBehaviors>
</behaviors>

WCF テスト クライアントを使用してデバッグ モードとリリース モードの両方でサービスをビルドして実行したところ、期待どおりに動作しました。 WCF テスト クライアント

また、IE ( ) を使用してサービスに ping を実行しhttp://localhost:<port-number)/HelloService.svc、サービス情報ページを表示して MEX にアクセスすることもできました。

HTH。

于 2013-05-22T23:39:36.257 に答える
2

問題は WCF 自体に関係していないことがわかりました。

サービス クラスで単純な Hello メソッドを呼び出していましたが、そのクラスのコンストラクターがログを設定していました (ただし、実際には Hello メソッドでログを使用していませんでした)。サービス クラス コンストラクターでインスタンス化されていたロギング ヘルパー クラスには、メソッド GetCallingMethodName がありました。このメソッドは、スタック トレースを調べて、メッセージをログに記録するクラスとメソッドの名前を特定し、ログ メッセージに名前を含めます。

問題の鍵は、GetCallingMethodName が、通常は GetCallingMethodName メソッド自体であるスタック トレースの最初のメソッド呼び出しをスキップしたことでした。Web サーバー上の 64 ビット JIT コンパイラーはメソッドをインライン化している必要があるため、スタック トレースに 2 番目のスタック フレームはありませんでした。そのため、スタック トレースの最初のフレームをスキップしようとすると、エラーが発生していました。

解決策は、2 番目のスタック フレームではなく、最初のスタック フレームからスタック トレースのウォークを開始することでした。

この問題は、Web サービスがデバッグ モードでサーバーにデプロイされたときに発生しませんでした。これは、コンパイラの最適化がオフになっているため、コンパイラがメソッドをインライン化できなかったためです。32 ビット JIT コンパイラは、サーバー上の 64 ビット コンパイラとは異なる方法でコードを最適化していたに違いないため、リリース モードの開発用 PC にも表示されませんでした。

于 2013-05-23T03:13:56.867 に答える