11

When using the ServiceHost.AddServiceEndpoint to add the custom ProtoEndpointBehavior I get the following exception :

System.ArgumentNullException: Value cannot be null. Parameter name: key at System.Collections.Generic.Dictionary2.FindEntry(TKey key) at System.Collections.Generic.Dictionary2.ContainsKey(TKey key) at System.ServiceModel.ServiceHostBase.ImplementedContractsContractResolver.ResolveContract(String contractName) at System.ServiceModel.ServiceHostBase.ServiceAndBehaviorsContractResolver.ResolveContract(String contractName) at System.ServiceModel.Description.ConfigLoader.LookupContractForStandardEndpoint(String contractName, String serviceName) at System.ServiceModel.Description.ConfigLoader.LookupContract(String contractName, String serviceName) at System.ServiceModel.ServiceHostBase.AddServiceEndpoint(ServiceEndpoint endpoint) at My.Service.Business.ServiceHandler.StartService(Type serviceType, String uri, SecureConnectionSettings secureConnectionSettings) in C:\My\Produkter\My Utveckling\Solution\My.Service.Business\ServiceHandler.cs:line 150

This is how the code looks like :

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;

I use to set this in config file like this :

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

Now I need to add it in code instead.

What is wrong?

MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
Banshee
  • 15,376
  • 38
  • 128
  • 219

2 Answers2

10

It's a known bug and there is workaround for it.

When obtaining instance of ContractDescription, use static method ContractDescription.GetContract(Type) instead of direct ContractDescription() constructor:

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

I was able to reproduce your problem and this workaround worked for me.

CodeFuller
  • 30,317
  • 3
  • 63
  • 79
1

The reason why you are seeing the exception is because ServiceEndpoint assumed you use configuration file. It is trying to retrieve & resolve your contract, binding and address that doesn't exist because you are not using config file.

ServiceEndpoint (see remarks)

Use this constructor when the binding and address for the endpoint are provided in configuration.

There are number of ways to create or retrieve a ContractDescription object:

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));

If you really insist to create ContractDescription programmatically you need to define some of the following:

  • ContractDescription
  • OperationDescription
  • MessageDescription
  • OperationBehaviorAttribute
  • And other stuff...

Or you can follow this blog as a kicker.

Have you tried CodeFuller's answer? His answer could make your life easier. I made a quick check and it work.

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();
        }
    }
}

Unfortunately, I could not attached an image "something's wrong with imgur" but it work on my web browser. Though I haven't tested using client app but I guess you are already near to the solution.

Tip : Don't mix configuration file and code because it is very difficult to maintain. "Which you probably knew" Good luck :)

jtabuloc
  • 2,479
  • 2
  • 17
  • 33