【问题标题】:AddServiceEndpoint throws key is null?AddServiceEndpoint 抛出键为空?
【发布时间】:2017-07-08 18:05:47
【问题描述】:

使用 ServiceHost.AddServiceEndpoint 添加自定义 ProtoEndpointBehavior 时,出现以下异常:

System.ArgumentNullException:值不能为空。参数名称: System.Collections.Generic.Dictionary2.FindEntry(TKey key) at System.Collections.Generic.Dictionary2.ContainsKey(TKey key) 处的键 System.ServiceModel.ServiceHostBase.ImplementedContractsContractResolver.ResolveContract(字符串 合同名称)在 System.ServiceModel.ServiceHostBase.ServiceAndBehaviorsContractResolver.ResolveContract(字符串 合同名称)在 System.ServiceModel.Description.ConfigLoader.LookupContractForStandardEndpoint(字符串 合同名称,字符串服务名称)在 System.ServiceModel.Description.ConfigLoader.LookupContract(字符串 合同名称,字符串服务名称)在 System.ServiceModel.ServiceHostBase.AddServiceEndpoint(ServiceEndpoint 端点)在 My.Service.Business.ServiceHandler.StartService(类型 serviceType, 字符串 uri,SecureConnectionSettings 安全连接设置)在 C:\我的\产品\我的 Utveckling\Solution\My.Service.Business\ServiceHandler.cs:150 行

这就是代码的样子:

ServiceHost serviceHost = null;
Console.WriteLine("Creating service " + serviceType.FullName);
serviceHost = new MyServiceHost(serviceType, new Uri(uri));

var endPointAddress = "";

HttpBindingBase binding = null;
if (secureConnectionSettings != null && secureConnectionSettings.Enabled)
{
    Console.WriteLine("Setting certificates");
    X509Store store = new X509Store(secureConnectionSettings.CertificateStore, secureConnectionSettings.CertificateLocation);
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByThumbprint, secureConnectionSettings.Thumbprint, true);
    store.Close();

    if (certs.Count > 0)
        serviceHost.Credentials.ServiceCertificate.SetCertificate(secureConnectionSettings.CertificateLocation,
                                                                secureConnectionSettings.CertificateStore,
                                                                X509FindType.FindByThumbprint,
                                                                secureConnectionSettings.Thumbprint);
    else
        throw new Exception("Could not finde certificate with thumbprint " + secureConnectionSettings.Thumbprint);

    endPointAddress = uri + "/BinaryHttpsProto";
    binding = CreateNetHttpsBinding(secureConnectionSettings);
}
else
{
    endPointAddress = uri + "/BinaryHttpProto";
    binding = CreateNetHttpBinding();
}

var endpoint = new System.ServiceModel.Description.ServiceEndpoint(new System.ServiceModel.Description.ContractDescription(typeof(IMyClientService).FullName), 
    binding, 
    new EndpointAddress(endPointAddress));

endpoint.EndpointBehaviors.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());
serviceHost.AddServiceEndpoint(endpoint);

Console.WriteLine("Starting service...");
serviceHost.Open();
Console.WriteLine("Service started successfully (" + uri + ")");
return serviceHost;

我习惯在配置文件中这样设置:

  <endpointBehaviors>
    <behavior name="protoEndpointBehavior">
      <protobuf />
    </behavior>
  </endpointBehaviors>

现在我需要在代码中添加它。

怎么了?

【问题讨论】:

  • 您发布的代码中的哪一行引发了该错误?
  • @FeryalBadili 在端点上抛出。EndpointBehaviors.Add 行。

标签: c# .net wcf endpoint


【解决方案1】:

这是一个known bug,有解决方法。

获取ContractDescription实例时,使用静态方法ContractDescription.GetContract(Type),而不是直接ContractDescription()构造函数:

var endpoint = new System.ServiceModel.Description.ServiceEndpoint(System.ServiceModel.Description.ContractDescription.GetContract(typeof(IMyClientService)), 
    binding, 
    new EndpointAddress(endPointAddress));

我能够重现您的问题,并且此解决方法对我有用。

【讨论】:

    【解决方案2】:

    您看到异常的原因是ServiceEndpoint 假设您使用配置文件。它正在尝试检索和解决您不存在的合同、绑定和地址,因为您没有使用配置文件。

    ServiceEndpoint(见备注)

    当端点的绑定和地址为 在配置中提供。

    create or retrieve a ContractDescription对象有多种方式:

    var contractUsingName = new ContractDescription("IProtoBufService");
    var contractUsingNameWithNameSpace = new ContractDescription("IProtoBufService", "http://www.tempuri.org");
    var contractUsingContractType = ContractDescription.GetContract(typeof(IProtoBufService));
    var contractUsingContractTypeAndObjectImp = ContractDescription.GetContract(typeof(IProtoBufService), ProtoBufService);
    var contractUsingContractTypeAndObjectType = ContractDescription.GetContract(typeof(IProtoBufService), typeof(ProtoBufService));
    

    如果您真的坚持以编程方式创建ContractDescription,则需要定义以下一些内容:

    • 合同说明
    • 操作说明
    • 消息描述
    • 操作行为属性
    • 还有其他东西...

    或者你可以关注这个blog 作为踢球者。

    您是否尝试过 CodeFuller 的答案?他的回答可以让你的生活更轻松。我做了一个快速检查,它可以工作。

    class Program
    {
        static void Main()
        {
            var baseAddress = new Uri("http://localhost:8080/ProtoBuf");
    
            using (var serviceHost = new ServiceHost(typeof(ProtoBufService), baseAddress))
            {
                var endpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IProtoBufService)),
                    new NetHttpBinding(),
                    new EndpointAddress(baseAddress));
    
                endpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());
                serviceHost.AddServiceEndpoint(endpoint);
    
                serviceHost.Open();
                Console.ReadKey();
            }
        }
    }
    

    很遗憾,我无法附上图片“imgur 出了点问题”,但它可以在我的网络浏览器上运行。虽然我没有使用客户端应用程序进行测试,但我猜你已经接近解决方案了。

    提示:不要混合配置文件和代码,因为它们很难维护。 “你可能知道”祝你好运:)

    【讨论】:

    • 谢谢!是的,CodeFuller 似乎解决了这个问题,但我仍在检查它是否真的解决了。
    猜你喜欢
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    相关资源
    最近更新 更多