2011-11-04 68 views
3

我試圖把幾個第三方Web服務的Web服務包裝。對於這個問題的緣故,我們會以兩個人的工作:動態命名空間切換

  1. OrderService
  2. AddressService

這兩種服務在不同的命名空間中定義相同的對象:

  1. OrderService.AuthenticationParameters
  2. AddressService.AuthenticationParameters

我希望能夠創建一個能夠檢測/切換名稱空間的單一基類。例如:

public abstract class BaseLogic 
{ 
    internal BaseLogic() 
    { 
     /* Initialize authParams */ 

     //Switch out/detect namespace here 
     this.authParams = new OrderService.AuthenticationParameters(); 
     this.authParams.accountName = "[MyAccountName]"; 
     this.authParams.userName = "[MyUserName]"; 
     this.authParams.password = "[MyPassword]"; 
    } 
} 

我見過幾個類似的問題。要麼他們不適用於我的情況,要麼我不能理解他們。

問題:是我想實現的可能嗎?如果可能的話,我是否過分複雜?

附加信息:事實上,將會有兩個以上的服務共享這個公共對象。供應商爲其提供的每個功能分支提供單獨的服務URL。

回答

2

有很多解決方案。

  • 讓您的服務代理類實現您自己的接口來公開方法,然後使用反射來構建一個類型。
  • 將這兩個服務包裝在另一個公開方法的類中,並且引用了兩個服務,然後簡單地提供一個切換參數以確定要使用哪個服務。
  • 通過自己的接口抽象服務的使用,並明確地爲每個服務編寫類(見下文)。

或者,如果你想通過動態和鴨打字玩,這似乎工作:

namespace ConsoleApplication42 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Type t1 = Type.GetType("ProviderOne.AuthService"); 

      dynamic service = Activator.CreateInstance(t1); 

      Console.WriteLine(service.GetUsername()); 

      Type t2 = Type.GetType("ProviderTwo.AuthService"); 

      service = Activator.CreateInstance(t2); 
      Console.WriteLine(service.GetUsername()); 

      Console.Read(); 
     } 
    } 
} 

namespace ProviderOne 
{ 
    public class AuthService 
    { 
     public string GetUsername() 
     { 
      return "Adam"; 
     } 
    } 
} 

namespace ProviderTwo 
{ 
    public class AuthService 
    { 
     public string GetUsername() 
     { 
      return "Houldsworth"; 
     } 
    } 
} 

請記住在具有相同簽名兩種服務都鉸鏈。

對於未來的其他服務,這取決於它。我從來沒有真正遇到過需要動態地從一個服務切換到另一個服務,以獲得相同的事情稍微不同的行爲。

也許這應該從你的應用程序的一方驅動?不是選擇適合的服務,只需實現兩個具有此變化行爲的類的版本 - 在其上放置一個通用接口,然後決定在運行時使用哪些類。然後該類本身將被直接編碼爲一個的服務。

interface IGetUsername 
{ 
    string GetUsername(); 
} 

class UsernameViaProviderOne : IGetUsername 
{ 
    public string GetUsername() 
    { 
     return new ProviderOne.AuthService().GetUsername(); 
    } 
} 

class UsernameViaProviderTwo : IGetUsername 
{ 
    public string GetUsername() 
    { 
     return new ProviderTwo.AuthService().GetUsername(); 
    } 
} 

然後決定是牢牢地掌握在您的客戶端代碼和消除了反射/動態類型的需求:

IGetUsername usernameProvider = null; 

if (UseProviderOne) 
    usernameProvider = new UsernameViaProviderOne(); 

... 

要勞動的時候,你總是可以得到非常SOA,並創建另一個服務,您的應用會與其他兩個服務進行匯聚。然後至少你的客戶端代碼不會看到大量的不同的服務,只會談到一個。

+0

很好的答案,很好的細節。我採用了「動態」方法,因爲目前看起來工作量最少。似乎運作良好。 –

+0

@JamesHill沒問題。只要注意'dynamic',記住通常由編譯器捕獲的簡單錯誤直到DLR運行時才能找到。 –

+0

雖然方法和屬性的返回類型是在該名稱空間內定義的類的一個類型,但仍存在問題。如果你所做的只是返回泛型類型,這個方法就可以正常工作。 – Xipooo

0

嗯,我唯一能想到的就是用反射來創建對象。問題是你必須再次使用反射來設置屬性,調用方法等,因爲我想你沒有共享接口。雖然它的很多工作可能會降低性能,但它的確有用。 看看ActivatorCreateInstance你可以傳遞一個完全合格的類名並創建你的實例。 然後,使用這個新創建的對象的類型,您可以搜索要修改的屬性。

-1

您可以使用#if。

#if true 
using MyService.X; 
using x=MyService.A; 
#endif 
#if false 
using MyService2.X; 
using x=MyService.B; 
#endif 

但是你不能在運行時改變它的編譯時間。

注意:不是一個好的編程習慣。但是這存在。