2

WCFクライアントの場合、IServiceProxyFactory資格情報を設定するためのインターフェイスがあります。

public interface IServiceProxyFactory<T>
{
    T GetServiceProxy();
}

public class ServiceProxy1 : IServiceProxyFactory<ServiceClient1>
{
    public ServiceClient1 GetServiceProxy()
    {
        var client = new ServiceClient1();
        // set credentials here
        return client;
    }
}

public class ServiceProxy2 : IServiceProxyFactory<ServiceClient2> { 
    // ... 
} 

質問からWCFクライアントの「使用」ブロックの問題に対する最善の回避策は何ですか?、そして私は次のようにヘルパーを作成しました:

public static class Service<TProxy, TClient>
    where TProxy : IServiceProxyFactory<TClient>, new()
    where TClient : ICommunicationObject
{
    public static IServiceProxyFactory<TClient> proxy = new TProxy();

    public static void Use(Action<TClient> codeBlock)
    {
        TClient client = default(TClient);
        bool success = false;
        try
        {
            client = proxy.GetServiceProxy();
            codeBlock(client);
            ((ICommunicationObject)client).Close();
            success = true;
        }
        finally
        {
            if (!success)
            {
                ((ICommunicationObject)client).Abort();
            }
        }
    }
}

そして、私はヘルパーを次のように使用します。

Service<ServiceProxy1, ServiceClient1>.Use(svc => svc.Method()); 

質問:

  1. TClientまたはTProxy(更新された)タイプを削除して、次を使用して呼び出すことができる方法はありますか?

    Service<ServiceProxy1>.Use(svc => svc.Method()); 
    

    または(更新)

    Service<ServiceClient1>.Use(svc => svc.Method()); 
    
  2. ICommunicationObjectとに使用するよりも良い方法はClose()ありAbort()ますか?

4

2 に答える 2

3
  • コード

    partial class TestClass {
        public static void TestMethod() {
            Service<ServiceProxy1>.Use(svc => svc.Method());
            Service<ServiceProxy1>.Use(svc => svc.Method());
            Service<ServiceProxy1>.Use(svc => svc.Method());
            Service<ServiceProxy2>.Use(svc => svc.Method());
        }
    }
    
    public partial interface IServiceProxyFactory<T> {
        T GetServiceProxy();
    }
    
    public partial class Service<T> where T: ServiceProxy, new() {
        public static void Use(Action<T> codeBlock) {
            using(var client=ServiceProxy.GetServiceProxy<T>().GetServiceProxy() as T)
                try {
                    codeBlock(client);
                }
                catch {
                    throw;
                }
        }
    }
    
    public abstract partial class ServiceProxy: CommunicationObject, IDisposable {
        public static T GetServiceProxy<T>() where T: ServiceProxy, new() {
            var proxy=m_List.FirstOrDefault(x => typeof(T).Equals(x.GetType())) as T;
    
            if(null==proxy) {
                proxy=new T();
                m_List.Add(proxy);
            }
    
            return proxy;
        }
    
        public abstract ServiceProxy GetServiceProxy();
        public abstract void Method();
    
        protected virtual void Dispose(bool disposing) {
            lock(ThisLock)
                if(!this.IsDisposed&&disposing) {
                    this.Close();
    
                    if(!this.IsDisposed)
                        this.Abort();
                }
        }
    
        public void Dispose() {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        ~ServiceProxy() {
            this.Dispose(false);
        }
    
        static List<ServiceProxy> m_List=new List<ServiceProxy>();
    }
    
    public partial class ServiceProxy1: ServiceProxy {
        protected override IAsyncResult OnBeginClose(
            TimeSpan timeout, AsyncCallback callback, object state
            ) {
            throw new NotImplementedException();
        }
    
        protected override IAsyncResult OnBeginOpen(
            TimeSpan timeout, AsyncCallback callback, object state
            ) {
            throw new NotImplementedException();
        }
    
        protected override void OnAbort() {
        }
    
        protected override void OnEndClose(IAsyncResult result) {
        }
    
        protected override void OnEndOpen(IAsyncResult result) {
        }
    
        protected override void OnClose(TimeSpan timeout) {
        }
    
        protected override void OnOpen(TimeSpan timeout) {
        }
    
        protected override TimeSpan DefaultCloseTimeout {
            get {
                return TimeSpan.Zero;
            }
        }
    
        protected override TimeSpan DefaultOpenTimeout {
            get {
                return TimeSpan.Zero;
            }
        }
    
        public override ServiceProxy GetServiceProxy() {
            var client=new ServiceProxy1();
            // set credentials here
            return client;
        }
    
        public override void Method() {
        }
    }
    
    public partial class ServiceProxy2: ServiceProxy1 {
        public override ServiceProxy GetServiceProxy() {
            var client=new ServiceProxy2();
            // set credentials here
            return client;
        }
    }
    

言及する何か:

  1. lock再入場しても安全です

  2. fromからなどの任意のタイプへの推論のまったく同じ宣言を行うことは不可能です。TGeneric<T>ServiseClientServiceProxy<ServiceClient>

  3. 2によると、ServiceProxyServiceClientはコード内でまったく同じものであるため、はありませんServiceClient

  4. ServiceProxyそれ自体は抽象的です。便宜上、3プラスにServiceClient変換する必要があるという要件については、 ;から派生します。そして、...のものよりも良い方法はありますか、それは実装しますICommunicationObjectServiceProxyCommunicationObjectIDisposible

  5. を継承する具象クラスの静的インスタンスの場合ServiceProxy、それぞれにインスタンスが1つだけあり、に格納されm_List、静的汎用バージョンを呼び出すGetServiceProxy<T>()だけでそれらを取得できます。これは、フライウェイトパターンに似ているようです。

  6. 5によると、インターフェイスIServiceProxyFactory<T>はまったく使用されていません。見た目と使い心地を良くするために、そこに配置するだけです。

  7. のインスタンスバージョンはGetServiceProxy()元の使用法のままですが、具象クラスはそれをオーバーライドする必要があります。

  8. このUseメソッドでは、作成されたクライアントがusingステートメントで使用されます。Usingステートメントで問題を回避する方法を読みましたが、例外を処理するための戦略がわからないようです。そのため、再スローしてます。

  9. 1によると、私は、継承されて使用される、アトミックに破棄するためのロックによるスレッドセーフな方法を検討しています。とはそれに応じてそこでやっています。IsDisposedThisLockCloseAbort

  10. ああ10!クラスServiceProxy2ServiceProxy1はサンプル用であり、からServiceProxy2派生していServiceProxy1ます。

コードは冗長に見えますが、実際には非常にシンプルなデザインです。問題について報告してください。修正を試みます。ウィッシュヘルプとグッドロック

于 2013-03-24T09:50:15.177 に答える
1

トリックを使ってServiceProxy1クラスをマージすることでそれを達成しました。ServiceClient1ServiceClient1 : IServiceProxyFactory<ServiceClient1>

public interface IServiceProxyFactory<T>
{
    // can have a better name like SetCredentials()
    T GetServiceProxy();
}

// Got rid of ServiceProxy1 class
public partial class ServiceClient1 : IServiceProxyFactory<ServiceClient1>
{
    public ServiceClient1 GetServiceProxy()
    {
        var client = this;
        // set credentials here
        //client.ClientCredentials = "";
        return client;
    }
}

public partial class ServiceClient2 : IServiceProxyFactory<ServiceClient2> { ... } 

public static class ServiceMod<TClient>
    where TClient : class, ICommunicationObject, IServiceProxyFactory<TClient>, new()
{
    public static TReturn Use<TReturn>(Func<TClient, TReturn> codeBlock)
    {
        TClient client = default(TClient);
        bool success = false;
        try
        {
            client = new TClient().GetServiceProxy();
            TReturn result = codeBlock(client);
            client.Close();
            success = true;
            return result;
        }
        finally
        {
            if (!success)
            {
                client.Abort();
            }
        }
    }
}

そして今、私はできる:

Service<ServiceClient1>.Use(svc => svc.Method());
于 2013-03-24T20:54:11.163 に答える