2012-07-10 59 views
1

我有一個.NET服務引用,我想將它封裝到單個可重用類中。在可重用類中封裝多個服務引用操作

我典型的調用看起來是這樣的:

// instantiate the api and set credentials 
ApiClient api = new ApiClient(); 
api.Credentials.UserName.UserName = "blah"; 
api.Credentials.UserName.Password = "blahblah"; 

// operation-specific search parameter object 
SomethingSearch search = new SomethingSearch(); 
search.Key = "blah"; 

Result[] result = api.GetSomething(search); 

api.Close(); 

其他電話中都被稱爲操作和搜索參數的對象而有所不同。

的事情是,我不知道如何傳遞到API操作(即GetSomething()和具體操作的搜索對象(SomethingSearch)的兩個類的名字。

會如何我做到這一點?我不是要求爲我做的工作,但我不知道從哪裏開始,我相信它與Func<T>和代表有關,但我對他們沒有經驗的尷尬

+1

有很多模式可以通過互聯網處理這些事情,你只需要確保你適當地關閉了你的服務並且不會[使用using語句的錯誤](http: //msdn.microsoft.com/en-us/library/aa355056.aspx)。 – 2012-07-10 22:37:31

+0

這[封裝服務](http://stackoverflow.com/a/6020625/1257607)也可能有幫助。但更多的是封裝整個事情。 – DanielV 2016-09-09 12:24:39

回答

3

我的一位同事開發了這個解決方案:

/// <summary> 
/// Proxy for executing generic service methods 
/// </summary> 
public class ServiceProxy 
{ 
    /// <summary> 
    /// Execute service method and get return value 
    /// </summary> 
    /// <typeparam name="C">Type of service</typeparam> 
    /// <typeparam name="T">Type of return value</typeparam> 
    /// <param name="action">Delegate for implementing the service method</param> 
    /// <returns>Object of type T</returns> 
    public static T Execute<C, T>(Func<C, T> action) where C : class, ICommunicationObject, new() 
    { 
     C svc = null; 

     T result = default(T); 

     try 
     { 
      svc = new C(); 

      result = action.Invoke(svc); 

      svc.Close(); 
     } 
     catch (FaultException ex) 
     { 
      // Logging goes here 
      // Service Name: svc.GetType().Name 
      // Method Name: action.Method.Name 
      // Duration: You could note the time before/after the service call and calculate the difference 
      // Exception: ex.Reason.ToString() 

      if (svc != null) 
      { 
       svc.Abort(); 
      } 

      throw; 
     } 
     catch (Exception ex) 
     { 
      // Logging goes here 

      if (svc != null) 
      { 
       svc.Abort(); 
      } 

      throw; 
     } 

     return result; 
    } 
} 

而且其採用的例子:

public class SecurityServiceProxy 
{ 

    public static UserInformation GetUserInformation(Guid userId) 
    { 
     var result = ServiceProxy.Execute<MySecurityService, UserInformation> 
     (
      svc => svc.GetUserInformation(userId) 
     ); 

     return result; 
    } 

    public static bool IsUserAuthorized(UserCredentials creds, ActionInformation actionInfo) 
    { 
     var result = ServiceProxy.Execute<MySecurityService, bool> 
     (
      svc => svc.IsUserAuthorized(creds, actionInfo) 
     ); 

     return result; 
    } 
} 

在這個假的情況下,我們使用的是從MySecurityServiceGetUserInformationIsUserAuthorized兩種方法。 GetUserInformationGuid作爲參數並返回UserInformation對象。 IsUserAuthorized需要一個UserCredentialsActionInformation對象,並返回一個bool用戶是否被授權。

此代理也是緩存可緩存服務調用結果的理想之處。

如果您需要向服務器發送參數,可能會有更通用的方式,但我認爲您需要爲其創建特定的代理。例如:

public interface ISecuredService 
{ 
    public UserCredentials Credentials { get; set; } 
} 

/// <summary> 
/// Proxy for executing generic UserCredentials secured service methods 
/// </summary> 
public class SecuredServiceProxy 
{ 
    /// <summary> 
    /// Execute service method and get return value 
    /// </summary> 
    /// <typeparam name="C">Type of service</typeparam> 
    /// <typeparam name="T">Type of return value</typeparam> 
    /// <param name="credentials">Service credentials</param> 
    /// <param name="action">Delegate for implementing the service method</param> 
    /// <returns>Object of type T</returns> 
    public static T Execute<C, T>(UserCredentials credentials, Func<C, T> action) where C : class, ICommunicationObject, ISecuredService, new() 
    { 
     C svc = null; 

     T result = default(T); 

     try 
     { 
      svc = new C(); 
      svc.Credentials = credentials; 

      result = action.Invoke(svc); 

      svc.Close(); 
     } 
     catch (FaultException ex) 
     { 
      // Logging goes here 
      // Service Name: svc.GetType().Name 
      // Method Name: action.Method.Name 
      // Duration: You could note the time before/after the service call and calculate the difference 
      // Exception: ex.Reason.ToString() 

      if (svc != null) 
      { 
       svc.Abort(); 
      } 

      throw; 
     } 
     catch (Exception ex) 
     { 
      // Logging goes here 

      if (svc != null) 
      { 
       svc.Abort(); 
      } 

      throw; 
     } 

     return result; 
    } 
} 
+0

這正是我一直在尋找的東西。太好了,謝謝! – 2012-07-11 22:19:37

+0

奇怪的是,你會如何將一個參數傳遞給代理?在我的具體情況下,'svc'需要一個包含用戶名和密碼的對象。 – 2012-09-14 00:00:11

+0

@Paperjam我已經更新了一個更具體的例子來說明如何將各種參數傳遞給服務方法調用。如果您想進一步澄清,請告訴我。 – 2012-09-14 01:20:15

1

您可以對大多數WCF實現採取類似的方法&創建一個定義API功能的接口&隱藏實現beh ind那個接口。下面是使用您的代碼示例一個簡單的例子:

class APIEngine :IApiProvider 
    { 
     //...Private stuff & other methods 
     T[] Search<T>(SearchArgs args) 
     { 
      //Error handling ommitted 
      T[] result; 

      switch(args.SearchType) 
      { 
       case(SearchType.GetSomething) 
        result = GetSomethingSearch(args.Key); 
        break; 
       // and so on 
      }  


      api.Close(); 
      return result; 
     } 
     Result[] GetSomethingSearch(Key searchKey) 
     { 
      ApiClient api = new ApiClient(); 
      api.Credentials.UserName.UserName = "blah"; 
      api.Credentials.UserName.Password = "blahblah"; 

      object SomethingSearch search = new SomethingSearch(); 
      search.Key = searchKey; 

      result = api.GetSomething(search); 
     } 
    } 


class SearchArgs 
{ 
    SearchType SearchType {get; set;} //Enum of search types 
    SearchKey Key {get; set;} //SearchKey would be parent class for different key types 
{ 

你會調用這個就像任何其它接口:

IApiProvider.Search(keyValue); 

其他一切可以在施工期間設置或重新設置以後通過專用的方法。讓我知道這是不是真的回答你的問題。

編輯:

使用的參數的包裝類可以讓你有一個可以通過的情況下下降,以確定基於您的檢索類別正確的類型採取任何數量的搜索類型的一個友好的搜索方法。

+0

事情是,我需要能夠指定使用哪個API操作和搜索對象。例如,SomethingSearch可以是SomethingElseSearch,GetSomething可以是GetSomethingElse。不同的搜索對象也有不同數量的參數。 – 2012-07-10 21:50:39

+0

如果您有任何疑問,請參閱我的編輯並讓我知道 – Chris 2012-07-10 22:20:55

相關問題