Last active
September 1, 2016 16:19
-
-
Save randyburden/4517014 to your computer and use it in GitHub Desktop.
Provides numerous service interceptors/hooks for a WCF service, endpoint, or method all wrapped up in a single attribute. You can derive from the ServiceInterceptorAttribute class to create your own custom interceptor attribute or use it in conjunction with a class that implements IServiceInterceptor. Update: This has graduated to it's own proje…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.ObjectModel; | |
using System.ServiceModel; | |
using System.ServiceModel.Channels; | |
using System.ServiceModel.Description; | |
using System.ServiceModel.Dispatcher; | |
namespace Utilities.Wcf.Interceptors | |
{ | |
/// <summary> | |
/// Provides numerous service interceptors/hooks for a WCF service, endpoint, or method. | |
/// </summary> | |
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true )] | |
public class ServiceInterceptorAttribute : Attribute, IServiceBehavior, IEndpointBehavior, IOperationBehavior, IParameterInspector | |
{ | |
private readonly Type _iServiceInterceptor; | |
public Type ServiceType; | |
#region Constructors | |
public ServiceInterceptorAttribute() | |
{ | |
} | |
/// <summary> | |
/// Initializes with an IServiceInterceptor. | |
/// </summary> | |
/// <param name="iServiceInterceptor">A type that implements IServiceInterceptor</param> | |
public ServiceInterceptorAttribute( Type iServiceInterceptor ) | |
{ | |
// Enforce the type to implement IServiceInterceptor | |
if ( !typeof( IServiceInterceptor ).IsAssignableFrom( iServiceInterceptor ) ) | |
throw new ArgumentException( string.Format( "Wrong type: {0} must implement IServiceInterceptor", iServiceInterceptor ) ); | |
_iServiceInterceptor = iServiceInterceptor; | |
} | |
#endregion Constructors | |
#region Implementation of 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 virtual 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 virtual 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 virtual void ApplyDispatchBehavior( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase ) | |
{ | |
ServiceType = serviceDescription.ServiceType; | |
foreach ( var endpoint in serviceDescription.Endpoints ) | |
{ | |
endpoint.Behaviors.Add( this ); | |
foreach ( var operation in endpoint.Contract.Operations ) | |
{ | |
if ( !operation.Behaviors.Contains( GetType() ) ) | |
{ | |
operation.Behaviors.Add( this ); | |
} | |
} | |
} | |
} | |
#endregion Implementation of IServiceBehavior | |
#region Implementation of IEndpointBehavior | |
/// <summary> | |
/// Implement to confirm that the endpoint meets some intended criteria. | |
/// </summary> | |
/// <param name="endpoint">The endpoint to validate.</param> | |
public virtual void Validate( ServiceEndpoint endpoint ) | |
{ | |
} | |
/// <summary> | |
/// Implement to pass data at runtime to bindings to support custom behavior. | |
/// </summary> | |
/// <param name="endpoint">The endpoint to modify.</param><param name="bindingParameters">The objects that binding elements require to support the behavior.</param> | |
public virtual void AddBindingParameters( ServiceEndpoint endpoint, BindingParameterCollection bindingParameters ) | |
{ | |
} | |
/// <summary> | |
/// Implements a modification or extension of the service across an endpoint. | |
/// </summary> | |
/// <param name="endpoint">The endpoint that exposes the contract.</param><param name="endpointDispatcher">The endpoint dispatcher to be modified or extended.</param> | |
public virtual void ApplyDispatchBehavior( ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher ) | |
{ | |
} | |
/// <summary> | |
/// Implements a modification or extension of the client across an endpoint. | |
/// </summary> | |
/// <param name="endpoint">The endpoint that is to be customized.</param><param name="clientRuntime">The client runtime to be customized.</param> | |
public virtual void ApplyClientBehavior( ServiceEndpoint endpoint, ClientRuntime clientRuntime ) | |
{ | |
} | |
#endregion Implementation of IEndpointBehavior | |
#region Implementation of IOperationBehavior | |
/// <summary> | |
/// Implement to confirm that the operation meets some intended criteria. | |
/// </summary> | |
/// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param> | |
public virtual void Validate( OperationDescription operationDescription ) | |
{ | |
} | |
/// <summary> | |
/// Implements a modification or extension of the service across an operation. | |
/// </summary> | |
/// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param><param name="dispatchOperation">The run-time object that exposes customization properties for the operation described by <paramref name="operationDescription"/>.</param> | |
public virtual void ApplyDispatchBehavior( OperationDescription operationDescription, DispatchOperation dispatchOperation ) | |
{ | |
dispatchOperation.ParameterInspectors.Add( this ); | |
} | |
/// <summary> | |
/// Implements a modification or extension of the client across an operation. | |
/// </summary> | |
/// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param><param name="clientOperation">The run-time object that exposes customization properties for the operation described by <paramref name="operationDescription"/>.</param> | |
public virtual void ApplyClientBehavior( OperationDescription operationDescription, ClientOperation clientOperation ) | |
{ | |
} | |
/// <summary> | |
/// Implement to pass data at runtime to bindings to support custom behavior. | |
/// </summary> | |
/// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param><param name="bindingParameters">The collection of objects that binding elements require to support the behavior.</param> | |
public virtual void AddBindingParameters( OperationDescription operationDescription, BindingParameterCollection bindingParameters ) | |
{ | |
} | |
#endregion Implementation of IOperationBehavior | |
#region Implementation of IParameterInspector | |
/// <summary> | |
/// Called before client calls are sent and after service responses are returned. | |
/// </summary> | |
/// <param name="operationName">The name of the operation.</param> | |
/// <param name="inputs">The objects passed to the method by the client.</param> | |
/// <returns>The correlation state that is returned as the correlationState parameter in AfterCall. Return null if you do not intend to use correlation state.</returns> | |
public virtual object BeforeCall( string operationName, object[] inputs ) | |
{ | |
object obj = null; | |
var interceptor = GetServiceInterceptor(); | |
if ( interceptor != null ) | |
{ | |
obj = interceptor.BeforeCall( operationName, inputs ); | |
} | |
return obj; | |
} | |
/// <summary> | |
/// Called after client calls are returned and before service responses are sent. | |
/// </summary> | |
/// <param name="operationName">The name of the invoked operation.</param> | |
/// <param name="outputs">Any output objects.</param> | |
/// <param name="returnValue">The return value of the operation.</param> | |
/// <param name="correlationState">Any correlation state returned from the BeforeCall method, or null.</param> | |
public virtual void AfterCall( string operationName, object[] outputs, object returnValue, object correlationState ) | |
{ | |
var interceptor = GetServiceInterceptor(); | |
if ( interceptor != null ) | |
{ | |
interceptor.AfterCall( operationName, outputs, returnValue, correlationState ); | |
} | |
} | |
#endregion Implementation of IParameterInspector | |
#region Public Methods | |
/// <summary> | |
/// Attempts to get an IServiceInterceptor. | |
/// </summary> | |
/// <remarks> | |
/// This method attempts to first use a passed in IServiceInterceptor. | |
/// If one was not passed in, then it attempts to use the current service instance | |
/// if it implements IServiceInterceptor otherwise it returns null. | |
/// </remarks> | |
/// <returns>An IServiceInterceptor</returns> | |
public IServiceInterceptor GetServiceInterceptor() | |
{ | |
if ( _iServiceInterceptor != null ) | |
{ | |
var instance = Activator.CreateInstance( _iServiceInterceptor ); | |
var serviceInterceptor = instance as IServiceInterceptor; | |
if ( serviceInterceptor != null ) | |
{ | |
return serviceInterceptor; | |
} | |
} | |
var serviceInstance = OperationContext.Current.InstanceContext.GetServiceInstance(); | |
if ( serviceInstance != null ) | |
{ | |
var interceptor = serviceInstance as IServiceInterceptor; | |
if ( interceptor != null ) | |
{ | |
return interceptor; | |
} | |
} | |
return null; | |
} | |
#endregion Public Methods | |
} | |
/// <summary> | |
/// When used in conjunction with the ServiceInterceptorAttribute, this interfaces methods | |
/// will be called at the appropriate time. | |
/// </summary> | |
public interface IServiceInterceptor | |
{ | |
/// <summary> | |
/// Called before client calls are sent and after service responses are returned. | |
/// </summary> | |
/// <param name="operationName">The name of the operation.</param> | |
/// <param name="inputs">The objects passed to the method by the client.</param> | |
/// <returns>The correlation state that is returned as the correlationState parameter in AfterCall. Return null if you do not intend to use correlation state.</returns> | |
object BeforeCall( string operationName, object[] inputs ); | |
/// <summary> | |
/// Called after client calls are returned and before service responses are sent. | |
/// </summary> | |
/// <param name="operationName">The name of the invoked operation.</param> | |
/// <param name="outputs">Any output objects.</param> | |
/// <param name="returnValue">The return value of the operation.</param> | |
/// <param name="correlationState">Any correlation state returned from the BeforeCall method, or null.</param> | |
void AfterCall( string operationName, object[] outputs, object returnValue, object correlationState ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment