.netwcfwcf-bindingwebhttpbindingwcf-behaviour

Can't add custom WebHttpBehavior: Cannot add two items with the same key


First a little bit of background: I have a REST service in WCF 4 that uses a WebHttpEndpoint. Rather than having explicit error handler in every service method, or even every service class, I'd like to have a centralized error handling that does logging and is able to wrap a nice custom message to pass up to the client.

I am attempting to do this by implementing IErrorHandler and adding that with a customer WebHttpBehavior:

public class ErrorHandlerBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        base.AddServerErrorHandlers(endpoint, endpointDispatcher);
    }
}

Then I'm adding that using an ExtensionElement:

<behaviors>
    <endpointBehaviors>
        <behavior>
            <authenticationInspector />
            <authorizationInspector />    
            <errorHandler />   
            <webHttp
                defaultBodyStyle="Bare"
                defaultOutgoingResponseFormat="Json"
                helpEnabled="true"  />      

If the whole approach to error handling seems like a bad idea, feel free to comment on that...

However, my question is why I'm getting this exception when the service tries to start:

[ArgumentException: Cannot add two items with the same key to SynchronizedKeyedCollection.]
   System.Collections.Generic.SynchronizedKeyedCollection`2.AddKey(K key, T item) +12277986
   System.Collections.Generic.SynchronizedKeyedCollection`2.InsertItem(Int32 index, T item) +38
   System.ServiceModel.Dispatcher.OperationCollection.InsertItem(Int32 index, DispatchOperation item) +53
   System.Collections.Generic.SynchronizedCollection`1.Add(T item) +78
   System.ServiceModel.Description.WebHttpBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) +2498
   System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +4275
   System.ServiceModel.ServiceHostBase.InitializeRuntime() +60
   System.ServiceModel.ServiceHostBase.OnBeginOpen() +27
   System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +50
   System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +318
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +206
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +651

[ServiceActivationException: The service '/api/Errors' cannot be activated due to an exception during compilation.  The exception message is: Cannot add two items with the same key to SynchronizedKeyedCollection..]
   System.Runtime.AsyncResult.End(IAsyncResult result) +688590
   System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +190

System.ServiceModel.Activation.AspNetRouteServiceHttpHandler.EndProcessRequest(IAsyncResult result) +6
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +96

It appears that either the webHttp or errorHandler behavior can exist by itself, but they won't coexist.


Solution

  • Your <errorHandler> already is-a WebHttpBehavior (which is the behavior associated with the <webHttp/> config element). You should update your behavior extension associated with <errorHandler> to understand the parameters you want to pass to the WebHttpBehavior, and have only that one.