using System; using System.Collections.ObjectModel; using System.Diagnostics; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; namespace Sony.Filtr.API.WCF { [AttributeUsage(AttributeTargets.Class)] public sealed class ErrorHandlerAttribute : Attribute, IServiceBehavior { public ErrorHandlerAttribute(params Type[] errorHandlerTypes) { const String ErrorHandlerTypeParameterName = "errorHandlerTypes"; // Checks whether the errorHandlerType parameter has been supplied if (errorHandlerTypes == null) { throw new ArgumentNullException(ErrorHandlerTypeParameterName); } if (errorHandlerTypes.Length == 0) { throw new ArgumentOutOfRangeException(ErrorHandlerTypeParameterName); } // 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(ErrorHandlerTypeParameterName); } } // Store the types ErrorHandlerTypes = errorHandlerTypes; ValidateHandlerTypes(); } public ErrorHandlerAttribute(params String[] errorHandlerTypeNames) { const String ErrorHandlerTypeNamesParameterName = "errorHandlerTypeNames"; // Checks whether the errorHandlerTypeName parameter has been supplied if (errorHandlerTypeNames == null) { throw new ArgumentNullException(ErrorHandlerTypeNamesParameterName); } if (errorHandlerTypeNames.Length == 0) { throw new ArgumentOutOfRangeException(ErrorHandlerTypeNamesParameterName); } // Loop through each item supplied for (Int32 index = 0; index < errorHandlerTypeNames.Length; index++) { String errorHandlerTypeName = errorHandlerTypeNames[index]; // Ensure that a value has been supplied if (String.IsNullOrEmpty(errorHandlerTypeName)) { throw new ArgumentNullException(ErrorHandlerTypeNamesParameterName); } } ErrorHandlerTypes = new Type[errorHandlerTypeNames.Length]; // Loop through each type for (Int32 index = 0; index < errorHandlerTypeNames.Length; index++) { // Get a reference to the type String errorHandlerTypeName = errorHandlerTypeNames[index]; Type handlerType = Type.GetType(errorHandlerTypeName, true, true); ErrorHandlerTypes[index] = handlerType; } ValidateHandlerTypes(); } public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters) { // Nothing to do here } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase 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 = serviceHostBase.ChannelDispatchers[dispatcherIndex] as ChannelDispatcher; Debug.Assert(dispatcher != null, "The dispatcher collection returned an item of an incorrect type"); // Loop through each error handler for (Int32 typeIndex = 0; typeIndex < ErrorHandlerTypes.Length; typeIndex++) { Type errorHandlerType = ErrorHandlerTypes[typeIndex]; // Create a new error handler instance IErrorHandler handler = Activator.CreateInstance(errorHandlerType) as IErrorHandler; Debug.Assert(handler != null, "Failed to create the IErrorHandler instance"); // Add the handler to the dispatcher dispatcher.ErrorHandlers.Add(handler); } } } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { // Nothing to do here } private void ValidateHandlerTypes() { Debug.Assert(ErrorHandlerTypes != null, "No ErrorHandlerTypes is null"); Debug.Assert(ErrorHandlerTypes.Length > 0, "No error handler types are available"); // Loop through each handler for (Int32 index = 0; index < ErrorHandlerTypes.Length; index++) { Type errorHandlerType = ErrorHandlerTypes[index]; // 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(); } } } private Type[] ErrorHandlerTypes { get; set; } } }