ServiceModel.DiscoveryClient(字符串endpointConfigurationName)抛出
本文关键字:抛出 endpointConfigurationName 字符串 DiscoveryClient ServiceModel | 更新日期: 2023-09-27 18:24:56
我有一个小型WCF客户端,我正试图通过应用程序配置文件为其进行服务发现配置,但无论何时:
// 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>
这是针对使用Visual Studio 2010 SP1的.NET Framework 4.0的。
DiscoveryClient(字符串)构造函数的此重载的文档表明,这应该使用App.config中标识的配置创建一个新的DiscoveryClient
实例。
其他人遇到过这种行为吗?如果遇到了,你是如何解决的?
您在配置文件中定义的"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.
好吧,在启用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
请注意,我假设这个问题在.NETFramework4.5/44.5.1中得到了解决——可能没有,但我目前无法测试。
如果其他人有比这更优雅或更高效的替代解决方案,请发布它来帮助他人。