1

私は最近、Visual Studio から自動生成されたコードに頼るのではなく、自分の WCF サービスを呼び出す独自の ChannelFactory ラッパーを書き始めました。

以前は、自動生成されたプロキシを使用して、エラー チェックのためにこれを行うことができました。

    protected AccessControlServiceClient AccessControlService
    {
        get
        {
            // Check if not initialized yet
            if (HttpContext.Current.Session["AccessControlServiceClient"] == null)
                HttpContext.Current.Session["AccessControlServiceClient"] = new AccessControlServiceClient();

            // If current client is 'faulted' (due to some error), create a new instance.
            var client = HttpContext.Current.Session["AccessControlServiceClient"] as AccessControlServiceClient;
            if (client.State == CommunicationState.Faulted)
            {
                try { client.Abort(); }
                catch { /* no action */ }

                client = new AccessControlServiceClient();
                HttpContext.Current.Session["AccessControlServiceClient"] = client;
            }

            return client;
        }
    }

ChannelFactor でこれをどのように処理すればよいですか? 何か問題が発生した場合にチャネルを処理し、再作成するためのベスト プラクティスは何ですか? たとえば、断続的なネットワーク接続、セッション タイムアウトなどです。

これは私のコードが現在どのように見えるかです:

ProxyBase.cs からのスニペット - チャネルの作成

private void Initialise()
{
    lock (_sync)
    {
        if (_channel != null) return;

        _channel = new ChannelFactory<T>(_serviceEndPointUri).CreateChannel();
    }
 }

UserManagementServiceClient.cs - IUserManagementService は WCF コントラクトです

public class UserManagementServiceClient : ProxyBase<IUserManagementService>
{
    public UserManagementServiceClient(string serviceEndPointUri)
        : base(serviceEndPointUri)
    {
    }

    public TokenResponse GetToken(TokenRequest request)
    {            
        return Channel.GetToken(request);
    }


    public LoginResponse Login(LoginRequest request)
    {
        return Channel.Login(request);
    }


    public LogoutResponse Logout(LogoutRequest request)
    {
        return Channel.Logout(request);
    }
}

そして最後に、これが私の MVC プロジェクトでの呼び出し方です

    protected UserManagementServiceClient UserManagementService
    {
        get
        {
            // Check if not initialized yet
            if (HttpContext.Current.Session["UserManagementServiceClient"] == null)
                HttpContext.Current.Session["UserManagementServiceClient"] = new UserManagementServiceClient("NetTcpBinding_UserManagementService");

            var client = HttpContext.Current.Session["UserManagementServiceClient"] as UserManagementServiceClient;

            return client;
        }
    }

そのため、現在、デフォルトの 10 分間のセッションが開始されるたびに、チャネルが既に閉じられているため、エラーが発生します。

ネットワークの切断やセッションのタイムアウトなどを処理するようにコードを強化するにはどうすればよいですか?

4

3 に答える 3

1

私はこのようなコードを使用します

public T Channel {
    get {
        lock (_channelLock) {
            if (!object.Equals(_channel, default(T))) {
                if (((ICommunicationObject)_channel).State == CommunicationState.Faulted) {
                    // channel has been faulted, we want to create a new one so clear it
                    _channel = default(T);
                }
            }

            if (object.Equals(_channel, default(T))) {
                // channel is null, create a new one
                Debug.Assert(_channelFactory != null);
                _channel = _channelFactory.CreateChannel();
            }
            return _channel;
        }
   }
于 2012-11-16T09:11:24.540 に答える
1

私は通常、操作ごとに新しいサービス インスタンスを使用します。このような:

public async Task<bool> IsOnline()
    {
        using (var service = new DebugService())
        {
            return await service.OnlineCheckAsync();
        }
    }

とりわけ、私のラッパーは、この記事に従って IDisposable を実装しています。そうすれば、操作を実行するたびにチャネルに障害が発生しているかどうかを心配する必要がなくなります。

編集

IDisposable 実装の元のリンクは壊れていますが、コードを以下に示します。

public void Dispose()
    {
        // The following code is from: http://www.vasylevskyi.com/2010/11/correct-wcf-client-proxy-closing.html
        try
        {
            if (this.State != CommunicationState.Closed && this.State != CommunicationState.Faulted)
            {
                ((ICommunicationObject)this).BeginClose(
                    (asr) =>
                    {
                        try
                        {
                            ((ICommunicationObject)this).EndClose(asr);
                        }
                        catch
                        {
                            this.Abort();
                        }
                    }, null
                );
            }
            else
            {
                this.Abort();
            }
        }
        catch (CommunicationException)
        {
            this.Abort();
        }
于 2012-11-19T20:10:21.033 に答える
0

CurrentInstance現在のプロジェクトでは、アクセサー モデルを使用するクライアント用のラッパー クラスを作成しました。ゲッターは、またはをチェック_client.Stateし、そのような場合に新しいクライアントを作成します。新しいクライアントの作成は、ラッパー コンストラクターに提供されるファクトリ デリゲートによって行われるため、クライアント インスタンスを作成する自由で一貫した方法があります。ClosingClosedFaulted

Sessionあなたのシナリオでは、クライアントを直接保存するのではなく、ラッパーをに保存することを意味します。その後、呼び出しwrapper.CurrentInstanceによって状態がチェックされ、その間にタイムアウトが発生した場合はバックグラウンドでクライアントが再作成されます。

このモデルは、堅牢なエラー処理 (物理的な切断、サーバーのクラッシュなど)、遅延初期化、新しいクライアントを作成した後の任意の初期化ロジック (私の場合はSubscribe、Callback チャネルを作成するメソッドを呼び出していますが、それは何でもかまいません)

これがあなたにとっても正しい方向になることを願っています。

于 2012-11-16T08:13:06.093 に答える