4

概要:

WCF REST サービスで、独自のカスタム エラー応答を使用して正しくない入力パラメーターを処理するにはどうすればよいですか?

詳細:

WCF REST サービスに次のインターフェイス メソッドがあります。

[OperationContract]
[WebGet(UriTemplate = "getitem?id={itemId}", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
[FaultContract(typeof(DataModel.Fault))]
DataModel.Item GetItem(int itemId);

GetItem メソッドの実装内で、エラー条件 (つまり、アイテムが存在しない) をキャッチし、WebFaultException を作成します。これは何の問題もなく動作します。

ただし、呼び出し元のクライアントが次の URL を呼び出すとします。

http://myserver.com/itemservice/getitem?id=abc

つまり、id の入力値は、GetItem メソッドで要求されるように int にキャストできません。

DataModel.Fault指定された id 値は int にキャストできないため、この呼び出しは正しく失敗しますが、コードが実行される前にこの失敗が発生するため、インターフェイス メソッドに割り当てられた FaultContract に従ってオブジェクトを返すことができません。

問題は、高レベルのエラー ハンドラーをフックして、このタイプのエラーをキャッチし、その後、WCF が生成する HTML エラーではなく、独自のフォールト構造を返すにはどうすればよいかということです。

リクエスト エラー サーバーでリクエストの処理中にエラーが発生しました。詳細については、サーバー ログを参照してください。

同じ質問の続きとして、クライアントが次のように呼び出した場合も同じことができるようにしたいと思います。

http://myserver.com/itemservice/gettitem?id=abc

URI のタイプミスに注意してください。getitem ではなく getitem (2 つの t)

4

1 に答える 1

1

インターフェイスを使用IErrorHandlerしてサービスを拡張します。

これにより、例外に対して適切な障害を提供できます。 この投稿は、独自のエラーハンドラーをサービスの動作に接続する方法を示しています。

私は個人的に単一のクラスを使用して、次のような必要なすべての要素を実装しています。

public class ErrorSavingServiceBahavior : BehaviorExtensionElement, IServiceBehavior, IErrorHandler
{
    private string m_sHostName;

    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        this.m_sHostName = serviceHostBase.Description.Name;
        foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
        {
            if (!chanDisp.ErrorHandlers.Contains(this))
            {
                chanDisp.ErrorHandlers.Add(this);
            }
        }
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
    }

    public bool HandleError(Exception error)
    {
        //my custom code
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        //my custom code
    }

    public override Type BehaviorType
    {
        get { return this.GetType(); }
    }

    protected override object CreateBehavior()
    {
        return this;
    }
}

とweb.configで拡張します:

<behaviors>
  <serviceBehaviors>
    <behavior name="BehaviorName">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
      <saveExceptions />
    </behavior>
  </serviceBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add
      name="saveExceptions"
      type="Namespace.Class, DLLName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    />
  </behaviorExtensions>
</extensions>
于 2012-05-23T17:28:53.880 に答える