2013-07-24 70 views
1

我有我想要配置通過應用程序配置文件服務發現小WCF客戶端 - 不過每當我這樣做:ServiceModel.Discovery.DiscoveryClient(字符串endpointConfigurationName)拋出ArgumentNullException

// Create a new DiscoveryClient instance from the 'DiscoveryEndpoint' 
// configuration in App.config 
DiscoveryClient discoveryClient = new DiscoveryClient("DiscoveryEndpoint"); 

我得到一個ArgumentNullException,Value cannot be null. Parameter name: contract。對DiscoveryClient構造函數的這種過載沒有contract參數,並且在App.config中正確指定了合約(請參見下文)。

下面是App.config中的有關章節:

<system.serviceModel> 
    <client> 
    <endpoint name="DiscoveryEndpoint" 
       contract="IExampleContract" 
       kind="dynamicEndpoint" 
       endpointConfiguration="DynamicEndpointConfiguration"/> 
    </client> 

    <standardEndpoints> 
    <dynamicEndpoint> 
     <standardEndpoint name="DynamicEndpointConfiguration"> 
     <discoveryClientSettings> 
      <endpoint kind="udpDiscoveryEndpoint"/> 
      <findCriteria duration="00:00:02"> 
      <types> 
       <add name="IExampleContract"/> 
      </types> 
      <scopes> 
       <add scope="urn://wcf.test.com/examples/exampleContract/development"/> 
      </scopes> 
      </findCriteria> 
     </discoveryClientSettings> 
     </standardEndpoint> 
    </dynamicEndpoint> 
    </standardEndpoints> 
</system.serviceModel> 

這在.NET框架4.0的針對性,使用Visual Studio 2010 SP1。

DiscoveryClient(string)構造函數的這種過載文檔表明這應該創建一個具有在App.config中標識的配置的新DiscoveryClient實例。

是否有其他人遇到過這種行爲,如果是的話,你是如何解決它的?

回答

0

OK,我花了很多時間在調試器與Enable .NET Framework source stepping選項啓用,並且我發現,這個異常被拋出的原因(可能)在該方式實現中的錯誤DiscoveryClient從配置文件實例化 - 調用堆棧有一個調用方式,它將null的硬編碼值傳遞給參數contract,該參數是引發原始異常的地方。因此,經過多次的搔抓和大量的搜索之後,我想出了以下解決方法(嗯,更像是總共HACK:!) - 我在這裏張貼這個帖子是爲了幫助任何其他人遇到同樣的問題。

// HACK: The following is a workaround for a bug in .NET Framework 4.0 
//  Discovery should be possible when setup from the App.config with the 
//  following three lines of code: 
// 
//   discoveryClient = new DiscoveryClient("DiscoveryEndpoint"); 
//   Collection<EndpointDiscoveryMetadata> serviceCollection = discoveryClient.Find(new FindCriteria(typeof(IExampleContract))).Endpoints; 
//   discoveryClient.Close(); 
// 
//  However, a bug in the Discovery Client implementation results in an 
//  ArgumentNullException when running discovery in this way. 
// 
//  The following code overcomes this limitation by manually parsing the 
//  standard WCF configuration sections of App.config, and then configuring 
//  the appropriate FindCriteria for a programmatically configured discovery 
//  cycle. This code can be replaced by the above three lines when either 
//   1. The bug in .NET Framework 4.0 is resolved (unlikely), or 
//   2. The application is retargeted to .NET Framework 4.5/4.5.1 
// 
//  To aid future developers, this HACK will be extensively documented 

// Load the App.config file into a ConfigurationManager instance and load the configuration 
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 

// Get the ServiceModel configuration group 
ServiceModelSectionGroup serviceModelGroup = ServiceModelSectionGroup.GetSectionGroup(configuration); 

// Get the StandardEndpoints configuration node 
StandardEndpointsSection section = serviceModelGroup.StandardEndpoints; 

// Get the DynamicEndpoint configuration node 
Configuration dynamicEndpointConfiguration = section["dynamicEndpoint"].CurrentConfiguration; 

// Get the first DynamicEndpoint configuration 
// HACK: This assumes only one DynamicEndpoint configuration exists 
//  No additional configurations will be interpreted. This should 
//  not pose a problem as typically a client will only access a 
//  single service instance. This can be extended if necessary 
//  at a later time. 
DynamicEndpointElement element = ((DynamicEndpointElement)serviceModelGroup.StandardEndpoints["dynamicEndpoint"].ConfiguredEndpoints[0]); 

// Set the required Contract Type 
// HACK: This is currently hard-coded to prevent the need to specify 
//  an AssemblyQualifiedName in the App.config file. This will 
//  not typically pose a problem as each client will typically 
//  only open a single service exposing a single, well-known, 
//  Contract Type 
FindCriteria criteria = new FindCriteria(typeof(IExampleContract)); 

// Add all required Scopes to the FindCriteria instance 
foreach (ScopeElement scopeElement in element.DiscoveryClientSettings.FindCriteria.Scopes) 
{ 
    criteria.Scopes.Add(scopeElement.Scope); 
} 

// Get the Discovery Duration 
criteria.Duration = element.DiscoveryClientSettings.FindCriteria.Duration; 

// Create a new Discovery Client instance 
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint()); 

// Retrieve the matching Service Endpoints via Dynamic Search 
Collection<EndpointDiscoveryMetadata> serviceCollection = discoveryClient.Find(criteria).Endpoints; 

// Close the Discovery Client 
discoveryClient.Close(); 

// HACK: END -- Process the results of Discovery 

請注意,我假設這個問題在.NET框架4.5/4.5.1解決 - 它可能不是,但我不能測試的時刻。

如果其他人有其他解決方案,比這更優雅或更高效,請發佈以幫助他人。

1

您在配置文件中定義的「DiscoveryEndpoint」實際上是服務客戶端端點,而不是DiscoveryClient端點。

下面應該工作:

var exampleContractChannelFactory = new ChannelFactory<IExampleContract>("DiscoveryEndpoint"); 
var exampleContractClient = exampleContractChannelFactory.CreateChannel(); 
// You can now invoke methods on the exampleContractClient 
// The actual service endpoint used by the client will be looked up dynamically 
// by the proxy using the DiscoveryClient class internally. 
相關問題