C# ServiceModel.Discovery.DiscoveryClient(字符串endpointConfigurationName)引发ArgumentNullException异常
我有一个小型WCF客户端,我正试图通过应用程序配置文件对其进行配置,以便进行服务发现,但每当我这样做时:C# ServiceModel.Discovery.DiscoveryClient(字符串endpointConfigurationName)引发ArgumentNullException异常,c#,wcf,discovery,C#,Wcf,Discovery,我有一个小型WCF客户端,我正试图通过应用程序配置文件对其进行配置,以便进行服务发现,但每当我这样做时: // Create a new DiscoveryClient instance from the 'DiscoveryEndpoint' // configuration in App.config DiscoveryClient discoveryClient = new DiscoveryClient("DiscoveryEndpoint"); 我得到一个ArgumentNullEx
// Create a new DiscoveryClient instance from the 'DiscoveryEndpoint'
// configuration in App.config
DiscoveryClient discoveryClient = new DiscoveryClient("DiscoveryEndpoint");
我得到一个ArgumentNullException
,值不能为null。参数名称:合同
。对于DiscoveryClient
构造函数的此重载,没有contract
参数,并且在App.config中正确指定了该contract(见下文)
以下是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>
构造函数指出,这应该使用App.config中标识的配置创建一个新的DiscoveryClient
实例
还有其他人遇到过这种行为吗?如果是,您是如何解决的?好的,我在启用启用.NET Framework源代码单步执行
选项的调试器中花费了很多时间,我发现引发此异常的原因是(可能是)DiscoveryClient
从配置文件实例化的实现方式中存在一个错误-调用堆栈中有一个调用方式,它将null
的硬编码值传递到contract
参数中,该参数就是引发异常的地方
因此,经过大量的思考和搜索,我想出了以下解决方法(更像是一个完全的黑客:
!)-我在这里发布这个方法是为了帮助其他可能遇到同样问题的人
// 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
//HACK:下面是针对.NET Framework 4.0中的一个bug的解决方法
//当从App.config使用
//以下三行代码:
//
//discoveryClient=新的discoveryClient(“DiscoveryEndpoint”);
//Collection serviceCollection=discoveryClient.Find(新的FindCriteria(typeof(IExampleContract))).Endpoints;
//discoveryClient.Close();
//
//但是,发现客户端实现中的错误会导致
//以这种方式运行发现时出现异常。
//
//下面的代码通过手动解析
//App.config的标准WCF配置部分,然后配置
//以编程方式配置的发现的相应FindCriteria
//循环。当以下任一情况发生时,此代码可替换为上述三行:
// 1. .NET Framework 4.0中的错误已解决(不太可能),或
// 2. 该应用程序被重新定位到.NET Framework 4.5/4.5.1
//
//为了帮助未来的开发人员,将广泛记录这种黑客行为
//将App.config文件加载到ConfigurationManager实例并加载配置
配置=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//获取ServiceModel配置组
ServiceModelSectionGroup serviceModelGroup=ServiceModelSectionGroup.GetSectionGroup(配置);
//获取StandardEndpoints配置节点
StandardEndpointsSection=serviceModelGroup.StandardEndpoints;
//获取DynamicEndpoint配置节点
配置dynamicEndpointConfiguration=节[“dynamicEndpoint”]。当前配置;
//获取第一个DynamicEndpoint配置
//HACK:这假设只存在一个DynamicEndpoint配置
//不会解释其他配置。这应该
//不会造成问题,因为客户端通常只访问
//单个服务实例。如有必要,可以扩展此功能
//后来。
DynamicEndpointElement=((DynamicEndpointElement)serviceModelGroup.StandardEndpoints[“dynamicEndpoint”]。配置的数据点[0]);
//设置所需的合同类型
//黑客:这是目前硬编码,以防止需要指定
//App.config文件中的AssemblyQualifiedName。这将
//通常不会像每个客户机那样造成问题
//只打开一个服务,公开一个,
//合同类型
FindCriteria标准=新的FindCriteria(typeof(IExampleContract));
//将所有必需的作用域添加到FindCriteria实例
foreach(元素中的ScopeElement ScopeElement.DiscoveryClientSettings.FindCriteria.Scopes)
{
criteria.Scopes.Add(scopeElement.Scope);
}
//获取发现持续时间
criteria.Duration=element.DiscoveryClientSettings.FindCriteria.Duration;
//创建新的发现客户端实例
DiscoveryClient DiscoveryClient=newdiscoveryclient(new-UdpDiscoveryEndpoint());
//通过动态搜索检索匹配的服务端点
Collection serviceCollection=discoveryClient.Find(条件).Endpoints;
//关闭发现客户端
discoveryClient.Close();
//HACK:END——处理发现的结果
请注意,我假设这个问题在.NET Framework 4.5/4.5.1中得到了解决-可能没有,但我目前无法测试它
如果其他人有比此更优雅或更高效的替代解决方案,请发布它以帮助其他人。好的,我在启用启用.NET Framework源代码单步执行
选项的调试器中花费了很多时间,我发现引发此异常的原因是(可能是)DiscoveryClient
从配置文件实例化的实现方式中存在一个错误-调用堆栈中有一个调用方式,它将null
的硬编码值传递到contract
参数中,该参数就是引发异常的地方
因此,经过大量的思考和搜索,我想出了以下解决方法(更像是一个完全的黑客:
!)-我在这里发布这个方法是为了帮助其他可能遇到同样问题的人
// 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
//HACK:下面是一篇文章