1

特定のヘッダーの存在を検証するために、カスタム WCF サービス (.net 3.5 SP1) へのすべてのポスト リクエストをインターセプトします。

私がこれまでに試したこと:

public class ServiceFactory : WebServiceHostFactory
{
    protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var result = base.CreateServiceHost(serviceType, baseAddresses);

        result.Opened += result_Opened;

        return result;
    }

    private void result_Opened(object sender, EventArgs e)
    {
        var ctx = HttpContext.Current;
        var request = ctx.Request;
        if (request.HttpMethod == "POST")
        {              
            // Validate if the request contains my header
            if(request.Headers["MyHeader"] != "42")
                throw new VeryBadThingsException("boom");
        }
    }
}

また、このファクトリを使用するように svc ファイルをセットアップしました。

これは時々機能しています。実際、すべての Web サービス呼び出しが open イベント ハンドラーによってフックされるわけではありません。Web サービスの実際の実装に到達したので、問題は Web サービス自体ではないと思います。

すべての受信リクエストをサービスに正しくフックするにはどうすればよいですか?

PS: 私の状況をもう少し詳しく説明すると、このサービスは SharePoint 2010 によってホストされています。つまり、web.config ファイルを変更することはできません (技術的には可能ですが、展開と保守が面倒です)。

そして、私は実際にクラスを継承しますMicrosoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory

4

3 に答える 3

1

メッセージ インスペクターを追加して、WCF パイプラインを拡張する必要があります。クライアントのメッセージ インスペクターはヘッダーの追加を担当し、サーバーのメッセージ インスペクターはヘッダーが存在するかどうかの検証を担当します。

グッド プラクティス: カスタム ヘッダーを作成する場合は、検索を容易にするカスタム名前空間を指定します。

public static class WCFSOAPNamespaces
    {
        private const string root = "http://www.schemas.productname.com/";
        public const string Headers = root + "headers/";
    }

サーバ

IDispatchMessageInspector、サーバーへのすべての着信メッセージを処理します。これは、サーバー上にヘッダーが存在するかどうかを確認する場所です。

public class DispatchMessageInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            const string headerName = "nameOfTheHeader";

            var someHeaderData = request.Headers.GetHeader<string>(headerName, WCFSOAPNamespaces.Headers);
            //someHeaderData is the content that you want to check for every request. Attention: it throws System.ServiceModel.MessageHeaderException if the header doesn't exist   

            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState) { }
    }

クライアント

は、クライアント上のIClientMessageInspectorメッセージを処理します。メッセージにカスタム ヘッダーを追加する必要がある場合は、ここを参照してください。カスタム ヘッダーを追加する必要がない場合は、この最初のコードにジャンプできます。

public class ClientMessageInspector : IClientMessageInspector
    {
        public void AfterReceiveReply(ref Message reply, object correlationState) { }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            const string headerName = "nameOfTheHeader";
            string headerContent = ""; //fill this variable with the content

            var header = new MessageHeader<string>(headerContent ?? string.Empty);
            var untyped = header.GetUntypedHeader(headerName, WCFSOAPNamespaces.Headers);
            request.Headers.Add(untyped);

            return null;
        }
    }

両方 (クライアントとサーバー)

クライアントにメッセージ インスペクターが必要ない場合でも、サーバー側アプリケーションにメッセージ インスペクションを追加するには、この構成が必要です。具体的にはEndpointBehavior、MessageInspector を処理するために が必要です。次に、このカスタム エンドポイント動作を使用するようにサービス エンドポイントを設定する必要があります。

この例では、2 つのインスペクタを同じビヘイビアに配置しましたが、必要に応じて別のビヘイビアを作成できます。

   public class EndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public EndpointBehavior() { }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new ClientMessageInspector());
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new DispatchMessageInspector());
        }

        public void Validate(ServiceEndpoint endpoint) { }

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

        protected override object CreateBehavior()
        {
            return new EndpointBehavior();
        }
    }

次に、この動作を使用するようにエンドポイントを設定します。

プログラムによる

...
ServiceEndpoint endpoint;
...
endpoint.Behaviors.Add(new EndpointBehavior());

設定

...
<services>
  <service name="...">
    <endpoint address="..." binding="..." contract="..." behaviorConfiguration="endpointBehaviorName" />
  </service>
...
<behaviors>
  ...
  <endpointBehaviors>
    <behavior name="endpointBehaviorName">
      <customEndpointBehavior />
    </behavior>
  </endpointBehaviors>
</behaviors>
...
<extensions>
  <behaviorExtensions>
    <add name="customEndpointBehavior" type="FullNamespace.EndpointBehavior , AssemblyName" />
  </behaviorExtensions>
</extensions>

これ以降、すべてのリクエストはこのポイントを通過します。それが役に立てば幸い。

于 2013-11-04T17:00:48.610 に答える