5

どのように始まったのかよくわからないという問題があります。以前は問題なく動作していたと確信していますが、変更を加えたことを覚えていません。

まず、動作しない理由に直接影響しない限り、セットアップに集中しすぎないようにしてください。私は、それが機能しない原因となっているのと同じくらい批判を求めていません。

HTTP ヘッダー認証を使用する API を公開しています。ソリューションでこの API からの操作を使用しています。ボイラープレート コードを回避するために、 CustomClientMessageInspectorと、ヘッダーをメッセージに追加する役割を担うCustomCredentialBehaviorを使用して、サービスを初期化するClientFactoryを作成しました。

サービスを使用する必要がある場合、コードは次のようになります。

IClientCredentials credentials = ClientCredentials.FromToken();
var service = ClientFactory.CreateClientInstance<API.Clients.ClientServiceClient>(credentials);

ClientFactory は次のようになります (あまり判断しないでください)。

public class ClientFactory
{
    public static T CreateClientInstance<T>(IClientCredentials clientCredentials)
    {

        T t = Activator.CreateInstance<T>();
        var factory = t.GetType().GetProperty("ChannelFactory");
        using (var scope = new OperationContextScope((IContextChannel) t.GetType().GetProperty("InnerChannel").GetValue(t,null)))
        {

            var endpointBehavior = new CustomCredentialBehavior(clientCredentials);
            if (((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.Any(p => p.GetType() == typeof(CustomCredentialBehavior)))
            {
                var behavior =
                    ((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.FirstOrDefault(
                        p => p.GetType() == typeof (CustomCredentialBehavior));
                ((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.Remove(behavior);
            }

            ((ChannelFactory)factory.GetValue((t),null)).Endpoint.Behaviors.Add(endpointBehavior);

            return t;
        }
    }
}

CustomEndpointBehavior:

public class CustomCredentialBehavior:IEndpointBehavior
{
    private IClientCredentials _clientCredentials { get; set; }

    public CustomCredentialBehavior(IClientCredentials clientCredentials)
    {
        _clientCredentials = clientCredentials;
    }



    public void Validate(ServiceEndpoint endpoint)
    {

    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {

    }

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

ClientMessageInspector:

public class ClientCredentialMessageInspector:IClientMessageInspector
{
    private IClientCredentials _clientCredentials;

    public ClientCredentialMessageInspector(IClientCredentials clientCredentials)
    {
        _clientCredentials = clientCredentials;
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
            var buffer = request.CreateBufferedCopy(Int32.MaxValue);
            request = buffer.CreateMessage();

            HttpRequestMessageProperty messageProperty =
                (HttpRequestMessageProperty) request.Properties["httpRequest"];
            messageProperty.Headers.Add("AccessKey", _clientCredentials.AccessKey.ToString());
            messageProperty.Headers.Add("ClientKey", _clientCredentials.ClientKey.ToString());
            messageProperty.Headers.Add("AuthorizationKey", _clientCredentials.AuthorizationKey);
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {

    }
}

私が直面している問題は、正しいエンドポイント動作で ClientFactory から返されたサービスを確認できても、ApplyClientBehavior() が呼び出されないことです。何らかの理由で、元のように WCF パイプラインを利用していないようです。

追加した EndpointBehavior が使用されるように、ClientFactory にインスタンスを作成させるにはどうすればよいですか?

編集私が見ているものを示すために、サービス操作が呼び出される直前のウォッチウィンドウのスクリーンショットを次に示します。すべての正しい値で初期化された私の CustomCredentialBehavior を示しています。

ここに画像の説明を入力

編集私はカルロスのアドバイス(コメントで)を取り、呼び出しを簡素化し、代わりに次の呼び出しを使用しました。サービス参照を使用する必要があるたびに定型コードを呼び出す必要がないように、元のコードのどこに問題があるかを突き止めたいと思います。

次のコードが機能します。

        API.Clients.Client client = new API.Clients.Client();
        client.Active = true;
        client.Enabled = true;
        client.Name = model.ClientName;

        API.Clients.ClientServiceClient service = new ClientServiceClient();
        service.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentialBehavior(ClientCredentials.FromToken()));
        var response = service.CreateClient(new CreateClientRequest() { Client = client });

最初のコードが機能しない理由と、これが機能する理由は何ですか?

4

1 に答える 1

4

ここで何かが欠けているかもしれませんが、なぜそんなに複雑なルートをたどるのかよくわかりません。

インターフェイス (Client クラスではない) コントラクトがある場合は、次の手順を実行します。

var factory = new ChannelFactory<T>(); //T is the interface of the service

factory.Endpoint.Behaviors.Add()あなたの行動を追加する方法を提供します。そして、実際のサービスを作成するには、呼び出すだけfactory.CreateChannel()T.

要約すると:

public T Create<T>()
{
    var factory = new ChannelFactory<T>();
    factory.Endpoint.Behaviors.Add(<here goes your behavior>);
    return factory.CreateChannel();
}

また、それに応じてクライアント チャネルを破棄することも忘れないでください。IoC を使用している場合、コンテナーはおそらくそれを処理できます (たとえば、Autofac はできます)。

于 2013-03-15T03:24:42.487 に答える