How to setup up web.config for WCF IErrorhandler
Asked Answered
R

2

12

Can't integrate IErrorHandler into my project with the correct web.config

I have a successfully working WCF that is being consumed by webclients in .net 4 but when trying to setup IErrorhandler as a global error logger as a catch all for all my service methods, things are failing fast - mainly to do with web.config part! Please help.

The three services are: IReport, IServiceCustomer, IServiceUser

Implemented IErrorHandler in a seperate class called MyErrorClass.cs like this:

namespace CustomerWcfService
{
public class WcfErrorHandler : IErrorHandler
{
   /// <summary>
    /// Enables the creation of a custom <see cref="T:System.ServiceModel.FaultException`1"/> that is returned from an exception in the course of a service method.
    /// </summary>
    /// <param name="error">The <see cref="T:System.Exception"/> object thrown in the course of the service operation.</param><param name="version">The SOAP version of the message.</param><param name="fault">The <see cref="T:System.ServiceModel.Channels.Message"/> object that is returned to the client, or service, in the duplex case.</param>
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        // can create custom error messages here
    }

    /// <summary>
    /// Enables error-related processing and returns a value that indicates whether the dispatcher aborts the session and the instance context in certain cases. 
    /// </summary>
    /// <returns>
    /// true if  should not abort the session (if there is one) and instance context if the instance context is not <see cref="F:System.ServiceModel.InstanceContextMode.Single"/>; otherwise, false. The default is false.
    /// </returns>
    /// <param name="error">The exception thrown during processing.</param>
    public bool HandleError(Exception error)
    {
        // log error to database using legacy error handler
        ErrorHandler.LogError(error);

        // Let the other ErrorHandler do their jobs
        return true;
    }
}

public class WcfErrorServiceBehaviour : IServiceBehavior
{
    /// <summary>
    /// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully.
    /// </summary>
    /// <param name="serviceDescription">The service description.</param><param name="serviceHostBase">The service host that is currently being constructed.</param>
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {   }

    /// <summary>
    /// Provides the ability to pass custom data to binding elements to support the contract implementation.
    /// </summary>
    /// <param name="serviceDescription">The service description of the service.</param><param name="serviceHostBase">The host of the service.</param><param name="endpoints">The service endpoints.</param><param name="bindingParameters">Custom objects to which binding elements have access.</param>
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {   }

    /// <summary>
    /// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects.
    /// </summary>
    /// <param name="serviceDescription">The service description.</param><param name="serviceHostBase">The host that is currently being built.</param>
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        var handler = new WcfErrorHandler();
        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
        {
            dispatcher.ErrorHandlers.Add(handler);
        }
    }
}

public class WcfErrorHandlerBehaviour : BehaviorExtensionElement
{
    /// <summary>
    /// Creates a behavior extension based on the current configuration settings.
    /// </summary>
    /// <returns>
    /// The behavior extension.
    /// </returns>
    protected override object CreateBehavior()  {   return new WcfErrorServiceBehaviour();  }

    /// <summary>
    /// Gets the type of behavior.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.Type"/>.
    /// </returns>
    public override Type BehaviorType   {   get { return typeof (WcfErrorServiceBehaviour); }   }
}
}

What should the web.config look like as I've tried a million combinations from various tutorials and answers on the net but doesnt get it working! This is how the original working extract of web.config looks when I'm not involving IErrorHandler

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>

Please can someone send this WCF noob the corrected web.config pleasee as I keep deleting and trying again and getting no where (i've lost so many days on this) :(

Rossi answered 14/9, 2012 at 14:15 Comment(1)
Just a word of support: we've all been there with "keep deleting and trying again...". If you find yourself cowboy/voodoo coding for too long without effect you may need to stop for a sec, and read up on the topic (MSDN, a book, etc) without trying to solve your problem at hand. Often enough (though not always :P), after doing that, solving the problem you were having seems easy.Hoey
S
15
<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
        <serviceMetadata httpGetEnabled="true" />
        <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
        <serviceDebug includeExceptionDetailInFaults="true" />
        <errorHandler/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  <extensions>
    <behaviorExtensions>
      <add name="errorHandler" type="CustomerWcfService.WcfErrorHandlerBehaviour, CustomerWcfService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
    </behaviorExtensions>
  </extensions>
</system.serviceModel>

And then apply your behavior to the service you want it to be applied to.

Edit :

sorry for the miss, but you actually need to remove any line-break and any additional white space in the type name in the extension definition (old WCF bug which force you to use the fully qualified name string in extension type declaration).

Special answered 14/9, 2012 at 14:43 Comment(6)
How to 'apply the behaviour to the service'? I wanted it to be to allRossi
You didn't provide a service section so I didn't write it down, but if that is WCF 4+ using a behavior tag with no name should apply to every service by default. If not, you'll have to set a name for your behavior and use behaviorConfiguration=yourbehaviorname in the service tag.Special
You may have to show me what you mean...but at the moment I'm getting an error: "The element 'behaviour' has an invalid child element 'errorHandler'. List of possible elements expected...blah blah"Rossi
Strange, I've copy and pasted your <system.serviceModel>...</system.serviceModel> in its entirety yet still get the same 'invalid child element' error. Tried removing breaks between tags inside the <extensions> section and within the names but still no luck :(Rossi
@user904538 I invented the type attribute because I don't know neither your dll name nor it's version, culture and public token. I put CustomerWcfService.WcfErrorHandlerBehaviour, CustomerWcfService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null and that's namespace.typename, assemblyName, version, culture, publicToken syntax. You should check for your own assembly name / version / culture and public token.Special
thats great Paciv...I still get the error but it compiles and runs great!...THANKYOU SOOO MUCH!!Rossi
P
8

It's a bit late, but for other users here is a better approach (in my opinion) and the code above only has to be changed a little bit

You can change:

    public class WcfErrorServiceBehaviour : IServiceBehavior

to:

    public class WcfErrorServiceBehaviourAttribute : Attribute, IServiceBehavior

Now you can use this as an attribute for your service-class like this:

    [WcfErrorServiceBehaviour]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
                     ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class MXServiceCommands : IMXServiceCommands
    {
    }

Hope this helps some others.

Prohibitive answered 22/5, 2015 at 8:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.