2013-03-21 33 views
2

對於WCF客戶端,我有一個IServiceProxyFactory接口來設置憑據。是否有可能擺脫服務類中的TClient泛型類型

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> { 
    // ... 
} 

從問題What is the best workaround for the WCF client `using` block issue?,我創建了一個幫手如下:

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. 有沒有辦法可以擺脫TClientTProxy(更新)型的,這樣我可以調用使用:

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

    OR (更新)

    Service<ServiceClient1>.Use(svc => svc.Method()); 
    
  2. 有沒有更好的辦法,而不是使用ICommunicationObjectClose()Abort()

+0

嗯......你可以改變類上的約束是IServiceProxy ,從類簽名刪除TClient,並添加TClient和該方法的約束? – JerKimball 2013-03-24 02:12:26

回答

1

我通過使用ServiceClient1 : IServiceProxyFactory<ServiceClient1>的招數將ServiceProxy1類合併到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()); 
+0

感謝您的賞金,成爲一名自學者也很好。此外,我實際上首先發現它應該是'Service 。使用(svc => svc.Method());'因爲在原始問題中籤署了'Action '。所以我認爲唯一可能的事情是'ServiceProxy'和'ServiceClient'是一回事。 – 2013-03-25 11:02:44

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. 這是不可能的,我做了逆轉推斷的完全一樣的聲明從T到任何類型的Generic<T>,如ServiseClientServiceProxy<ServiceClient>

  3. 根據2,ServiceProxyServiceClient在代碼中是一樣的,所以沒有ServiceClient

  4. ServiceProxy本身是摘要。對於ServiceClient的要求需要轉換爲ICommunicationObject並且根據3加爲了方便的原因,ServiceProxy來自CommunicationObject;然後爲難道還有比...的東西,它實現IDisposible

  5. 對於它繼承ServiceProxy,混凝土類的靜態實例的每位將有只有一個例如一個更好的方式,和存儲在m_List,並調用靜態通用版本GetServiceProxy<T>()只是讓他們。這看起來更像是flyweight模式。

  6. 根據5,界面IServiceProxyFactory<T>根本沒有使用,只是把它放在那裏看起來很愉快。

  7. GetServiceProxy()的實例版本保持原來的用法,但具體的類將需要覆蓋它。

  8. Use方法中,所創建的客戶端用於使用語句。我已閱讀Avoiding Problems with the Using Statement,但似乎我不知道您想要處理例外的策略,因此我只需嘗試重新調整

  9. 根據1,我被鎖考慮線程安全方式處置原子,繼承IsDisposed和使用ThisLockCloseAbort正在那裏做相應的。

  10. 哦十! ServiceProxy2ServiceProxy1僅供參考,ServiceProxy2來自ServiceProxy1

該代碼看起來很冗長,但實際上非常簡單的設計。只要報告我的問題,我會盡力糾正它。希望有助於和好LOCK

+1

只是供參考:對於第八點:Dispose不應該拋出,甚至更多,你應該可以安全地調用Dispose對已經處置的對象多次處理。沒有「使用時隱藏異常」這樣的問題 - 問題在於一個Dispose方法無效執行 – quetzalcoatl 2013-03-24 10:02:01

+0

@quetzalcoatl:哦,當然。我主要假設我不知道是否有可能拋出,甚至在處置之前。所以留下一個*嘗試和重新拋出*應該是適用的方式。非常感謝你! – 2013-03-24 10:15:14

+0

@KenKin,我最終回答如下。但是你用'偏'來推動我朝着正確的方向前進,所以我要給你賞金。 – hIpPy 2013-03-25 05:27:35

相關問題