mark
mark

Reputation: 62886

The value could not be added to the collection, as the collection already contains an item of the same type ...

I need to customise each method in a WCF service - add logging.

So, I install a dedicated operation behavior for each operation when the service host is created:

public class CoreServiceHostFactory : ServiceHostFactory
{
    #region Overrides of ServiceHostFactory

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var host = base.CreateServiceHost(serviceType, baseAddresses);
        var operationBehavior = new WcfOperationBehavior();
        host.Description.Endpoints
            .SelectMany(e => e.Contract.Operations)
            .ForEach(o => o.Behaviors.Add(operationBehavior));

        return host;
    }

    #endregion
}

It works locally, but when deployed in QA fails with

The value could not be added to the collection, as the collection already contains an item of the same type: ... This collection only supports one instance of each type. Parameter name: item

The relevant section of the web.config is:

<services>
    <service name="DeviceServices.DeviceService" behaviorConfiguration="SLDeviceServices.ServiceBehavior">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="StandardBindingSSL" contract="DeviceServices.IDeviceService">
        </endpoint>
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="StandardBinding" contract="DeviceServices.IDeviceService">
        </endpoint>
    </service>
    <service name="DeviceServices.DeviceServiceJSON" behaviorConfiguration="SLDeviceServices.ServiceBehavior">
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="StandardBindingSSL" contract="DeviceServices.DeviceServiceJSON" behaviorConfiguration="DeviceServices.JSONDeviceServiceBehavior">
        </endpoint>
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="StandardBinding" contract="DeviceServices.DeviceServiceJSON" behaviorConfiguration="DeviceServices.JSONDeviceServiceBehavior">
        </endpoint>
    </service>
</services>
<behaviors>
    <serviceBehaviors>
        <behavior name="SLDeviceServices.ServiceBehavior">
            <serviceMetadata httpsGetEnabled="false" />
            <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
        <behavior name="DeviceServices.JSONDeviceServiceBehavior">
            <webHttp />
        </behavior>
    </endpointBehaviors>
</behaviors>

I fail to understand what is the problem. Anyone?

Upvotes: 2

Views: 3351

Answers (2)

pasha goroshko
pasha goroshko

Reputation: 199

The problem when you access multiple services. Need to check for duplicates when adding operation behavior

host.Description.Endpoints
    .Select(e => e.Contract)
    .Distinct()
    .SelectMany(c => c.Operations)
    .ForEach(o => 
    {
       if(o.Behaviors.Any(x=> x.GetType().Equals(typeof(WcfOperationBehavior))))
       {
          o.Behaviors.Add(operationBehavior));
       }
    });

Upvotes: 0

mark
mark

Reputation: 62886

I found the root cause. In QA the service has two endpoints - http and https, but both are bound to the same Contract.

Hence the code

host.Description.Endpoints
    .SelectMany(e => e.Contract.Operations)
    .ForEach(o => o.Behaviors.Add(operationBehavior));

traverses the same Contract twice. The fix is:

host.Description.Endpoints
    .Select(e => e.Contract)
    .Distinct()
    .SelectMany(c => c.Operations)
    .ForEach(o => o.Behaviors.Add(operationBehavior));

Upvotes: 2

Related Questions