views:

192

answers:

1

Had no luck with getting it working via config files, so decided to attempt to go the more robust route of doign it via class level attributes. If I can get this working it is clearly a great way of wrapping exceptions in Faults in the service layer withou trepeating lots of code.

However the code in the attribute never seems to get run - despite the code that defines the attribute compiling perfectly well and being recognised by the IDE. I have ran out of things to read regarding solving this - the exception just to be handled and just gets thrown.

I have also borrowed and chopped down a piece of code found on CodePlex that is on rorys site to simplify it for this problem without changing its function (removed redundant overloads)

this is driving me insane ... please help! :D

Rory Primrose - attribute implementation

Rory Primrose - IErrorHandlerImplementation

The code:

The Service interface and implementation

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [FaultContract(typeof(FaultException))]
    string GetData(int value);
}

[ErrorHandler(typeof(KnownErrorHandler))]
public class Service1 : IService1
{
    public string GetData(int value)
    {
        throw new Exception("This exception should get handled.");
    }
}

KnownErrorHandler Implementation:

public class KnownErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        Trace.WriteLine(error.ToString());  
       return true;  
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        FaultException faultException = new FaultException("Server error encountered. All details have been logged.");  
         MessageFault messageFault = faultException.CreateMessageFault();  
         fault = Message.CreateMessage(version, messageFault, faultException.Action); 
    }
}

Attribute definition - doubt the problem is here. I am fairly sure it is in how i am using this piece of code.

   [AttributeUsage(AttributeTargets.Class)]
    public sealed class ErrorHandler : Attribute, IServiceBehavior
    { 
        public ErrorHandler(Type errorHandler)
        {
            if (errorHandler == null)
            {throw new ArgumentNullException("errorHandler");}
            Type[] errorHandlerTypes = new[] { errorHandler };
            Initialize(errorHandlerTypes);
        }   

        public void AddBindingParameters(
            ServiceDescription serviceDescription,
            ServiceHostBase serviceHostBase,
            Collection<ServiceEndpoint> endpoints,
            BindingParameterCollection bindingParameters)
        {
            // Nothing to do here
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            if (serviceHostBase == null)
            {
                throw new ArgumentNullException("serviceHostBase");
            }

            // Loop through each channel dispatcher
            for (Int32 dispatcherIndex = 0; dispatcherIndex < serviceHostBase.ChannelDispatchers.Count; dispatcherIndex++)
            {
                // Get the dispatcher for this index and cast to the type we are after
                ChannelDispatcher dispatcher = (ChannelDispatcher)serviceHostBase.ChannelDispatchers[dispatcherIndex];

                // Loop through each error handler
                for (Int32 typeIndex = 0; typeIndex < ErrorHandlerTypes.Count; typeIndex++)
                {
                    Type errorHandlerType = ErrorHandlerTypes[typeIndex];

                    // Create a new error handler instance
                    IErrorHandler handler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);

                    // Add the handler to the dispatcher
                    dispatcher.ErrorHandlers.Add(handler);
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        { }


        private void Initialize(Type[] errorHandlerTypes)
        {
            const String ErrorHandlerTypesParameterName = "errorHandlerTypes";

            if (errorHandlerTypes == null)
            {
                throw new ArgumentNullException(ErrorHandlerTypesParameterName);
            }

            if (errorHandlerTypes.Length == 0)
            {
                throw new ArgumentOutOfRangeException(ErrorHandlerTypesParameterName);
            }

            List<String> typeNames = new List<String>(errorHandlerTypes.Length);

            // Loop through each item supplied
            for (Int32 index = 0; index < errorHandlerTypes.Length; index++)
            {
                Type errorHandlerType = errorHandlerTypes[index];

                // Check if the item supplied is null
                if (errorHandlerType == null)
                {
                    throw new ArgumentNullException(ErrorHandlerTypesParameterName);
                }

                // Check if the type doesn't define the IErrorHandler interface
                if (typeof(IErrorHandler).IsAssignableFrom(errorHandlerType) == false)
                {
                    // We can't use this type
                    throw new InvalidCastException();
                }

                String assemblyQualifiedName = errorHandlerType.AssemblyQualifiedName;

                if (typeNames.Contains(assemblyQualifiedName) == false)
                {
                    typeNames.Add(assemblyQualifiedName);
                }
                else
                {
                    throw new ArgumentException(
                        String.Format(CultureInfo.CurrentCulture, "Duplicate ErrorType Provided", assemblyQualifiedName));
                }
            }

            // Store the types
            ErrorHandlerTypes = new ReadOnlyCollection<Type>(errorHandlerTypes);
        }

        /// <summary>
        /// Gets the error handler types.
        /// </summary>
        /// <value>
        /// The error handler types.
        /// </value>
        public ReadOnlyCollection<Type> ErrorHandlerTypes
        {
            get;
            private set;
        }
    }
A: 

It's very hard to help you out here because you haven't provided any information about what is happening in your application.

  • Why is it not working?
  • What is happening (expected vs actual behavior/outcomes)?
  • What exceptions do you get on your client?
  • Do you have tracing set up?
  • Is there anything in the event log
  • What's your WCF hosting scenario (winforms, windows service, IIS, casini)?
  • Have you put breakpoints in the error handler?
  • What does your code look like?
  • What does your config look like?
Rory Primrose
turns out the code works fine as is ... iis on the computer i ws working on was broken. There should be no need for web config modification because this method of implementation is supposed to be totally independant.Hosting is IIS on windows 7 and none of the breakpoints outside the main contract call could be hit - they were on every method entry. Nothing was being traced out ... its as if the code wasn't there after compile - attribute tag caused no exception and was happy.Anyway its your code that i posted from your blog, so i guess the answer is yours. Thanks a lot for the blog posts.
John Nicholas
I'm glad it worked out for you :) I'm finding that I need to step into a WCF client proxy call in order to be able to hit breakpoints within a hosted service. Maybe that is the issue you were having if you were stepping over the WCF call or run running with no client breakpoints.
Rory Primrose
I was runnign with breakpoints and was stepping into the service ... it really was IIs being wierd. I reinstalled my machine and it worked perfectly first time.
John Nicholas