C# ServiceModel.Discovery.DiscoveryClient(字符串endpointConfigurationName)引发ArgumentNullException异常

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

我有一个小型WCF客户端,我正试图通过应用程序配置文件对其进行配置,以便进行服务发现,但每当我这样做时:

// 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:下面是一篇文章