Skip to content

Instantly share code, notes, and snippets.

@kkoziarski
Last active April 5, 2016 06:33
Show Gist options
  • Save kkoziarski/d092f23266ea9658d76c to your computer and use it in GitHub Desktop.
Save kkoziarski/d092f23266ea9658d76c to your computer and use it in GitHub Desktop.
WCF Behavior Extension - validation on methods invoking
namespace WCFBehaviorExtension
{
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
public class CustomValidationOperationInvoker : IOperationInvoker, IParameterInspector
{
private readonly IOperationInvoker originalInvoker;
private readonly string operationName;
public CustomValidationOperationInvoker(DispatchOperation operation, OperationDescription operationDescription)
{
this.originalInvoker = operation.Invoker;
this.operationName = operation.Name;
}
#region IOperationBehavior Members
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
OperationContext operationContext = OperationContext.Current;
ServiceSecurityContext securityContext = ServiceSecurityContext.Current;
// VALIDATION LOGIC GOES HERE
string user = null;
bool isAnonymous = true;
if (securityContext != null)
{
user = securityContext.PrimaryIdentity.Name;
isAnonymous = securityContext.IsAnonymous;
}
Uri remoteAddress = operationContext.Channel.LocalAddress.Uri;
string sessionId = operationContext.SessionId;
MessageVersion messageVersion = operationContext.IncomingMessageVersion;
Trace.WriteLine("Username: " + user);
Trace.WriteLine("Is Anonymoys" + isAnonymous);
Trace.WriteLine("Server address: " + remoteAddress);
Trace.WriteLine("Session id: " + sessionId);
Trace.WriteLine("Message version: " + messageVersion);
Trace.WriteLine("Operation:" + this.operationName);
Trace.WriteLine("Arguments:");
foreach (object input in inputs)
Trace.WriteLine(input);
object result = this.originalInvoker.Invoke(instance, inputs, out outputs);
return result;
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return this.originalInvoker.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult asyncResult)
{
object result = this.originalInvoker.InvokeEnd(instance, out outputs, asyncResult);
return result;
}
public object[] AllocateInputs()
{
return this.originalInvoker.AllocateInputs();
}
public bool IsSynchronous
{
get { return this.originalInvoker.IsSynchronous; }
}
#endregion
#region IParameterInspector Members
public object BeforeCall(string operationName, object[] inputs)
{
return null;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
}
#endregion
}
#region OperationBehavior - add as attribute on method (operation)
/// <summary>
/// Use this to add validation to a single method, instead of all methods in servie
/// Example usage - add as attribute on method (operation):
/// *[OperationContract]
/// *[CustomValidationOperation]
/// *string Reverse(string input);
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CustomValidationOperationAttribute : Attribute, IOperationBehavior
{
public bool IncludeParameterInspector { get; set; }
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
var invoker = new CustomValidationOperationInvoker(dispatchOperation, operationDescription);
dispatchOperation.Invoker = invoker;
if (this.IncludeParameterInspector)
{
dispatchOperation.ParameterInspectors.Add(invoker);
}
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) {}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) {}
public void Validate(OperationDescription operationDescription) {}
}
#endregion
#region ServiceBehavior - add as attribute on Service implementation class
/// <summary>
/// Use this to add validation to all methods (operations) in the service
/// Example usage - add as attribute on Service implementation class:
/// [CustomValidationServiceBehavior]
/// public class ExampleService : IExampleService
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class CustomValidationServiceBehaviorAttribute : Attribute, IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
IOperationBehavior behavior = new CustomValidationOperationBehavior();
operation.Behaviors.Add(behavior);
}
}
}
public void AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}
public class CustomValidationOperationBehavior : IOperationBehavior
{
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
var invoker = new CustomValidationOperationInvoker(dispatchOperation, operationDescription);
dispatchOperation.Invoker = invoker;
if (this.IncludeParameterInspector)
{
dispatchOperation.ParameterInspectors.Add(invoker);
}
}
public bool IncludeParameterInspector { get; set; }
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
public void Validate(OperationDescription operationDescription) { }
}
#endregion
}
namespace WCFBehaviorExtension
{
using System;
using System.ServiceModel;
[ServiceContract]
public interface IExampleService
{
[OperationContract]
//[CustomValidationOperation]
string Reverse(string input);
}
[CustomValidationServiceBehavior]
public class ExampleService : IExampleService
{
public string Reverse(string input)
{
return new string(input.Reverse().ToArray());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment