ServiceModel.Discovery.DiscoveryClient(字符串端点配置名称)抛出ArgumentNullException

问题描述 投票:0回答:2

我有一个小型 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
contract
构造函数的重载没有
DiscoveryClient
参数,并且在 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 Framework 4.0,使用 Visual Studio 2010 SP1。

有关 DiscoveryClient(string) 构造函数重载的文档表明,这应该使用 App.config 中标识的配置创建一个新的

DiscoveryClient
实例。

还有其他人遇到过这种行为吗?如果有,你是如何解决的?

c# wcf wcf-discovery
2个回答
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.

0
投票

好的,我在启用了

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 Framework 4.5 / 4.5.1 中得到解决 - 可能没有,但我目前无法对此进行测试。

如果其他人有比这更优雅或更高效的替代解决方案,请发布它以帮助其他人。

© www.soinside.com 2019 - 2024. All rights reserved.