This can be done by implementiong IParameterInspector which has only two methods:
1. public object BeforeCall(string operationName, object[] inputs)
2. public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
Real world scenario
1. Some common validation which need to be done for large number of operations. For example name field which accepts only [a-zA-Z]. It would't be hard to implement this in the method (operation) itself, but if you need to do this for lot of cases then it might make sense to implement the validation logic as an IParameterInspector extension that can be declaratively applied to any operation.
2. To capture performance timing. The parameter inspector interface methods are called really close to the actual method invocation both on the client and on the server, so the time difference between before and after call can be calculated as operation duration.
class NameValidationParameterInspector : IParameterInspector { readonly int _nameParamIndex; const string NameFormat ="[a-zA-Z]"; public NameValidationParameterInspector() : this(0) { } public NameValidationParameterInspector(int nameParamIndex) { _nameParamIndex = nameParamIndex; } public object BeforeCall(string operationName, object[] inputs) { //Access the parameter. you need to know the index of the parameter. In this case we will always validate the //first parameter which is being passed string nameParam = inputs[_nameParamIndex] as string; if (nameParam != null) if (!Regex.IsMatch( nameParam, NameFormat, RegexOptions.None)) throw new FaultException( "Invalid name. Only alphabetical character"); return null; } public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState){} }And now add this to behavior
public class NameValidationOperationBehavior : Attribute, IOperationBehavior { public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { NameValidationParameterInspector nameValidationParameterInspector = new NameValidationParameterInspector(); clientOperation.ParameterInspectors.Add(nameValidationParameterInspector); } public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters){} public void Validate(OperationDescription operationDescription){} public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { NameValidationParameterInspector nameValidationParameterInspector = new NameValidationParameterInspector(); dispatchOperation.ParameterInspectors.Add(nameValidationParameterInspector); } }And now you can decorate any operation with attribute NameValidationOperationBehavior.
In this example I calculate the operation time
public class OperationProfilerParameterInspector : IParameterInspector { public object BeforeCall(string operationName, object[] inputs) { return DateTime.Now; } public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) { DateTime endCall = DateTime.Now; DateTime startCall = (DateTime)correlationState; TimeSpan operationDuration = endCall.Subtract(startCall); } }And now add to the EndpointBehavior
public class OperationProfilerEndpointBehavior : IEndpointBehavior { public void Validate(ServiceEndpoint endpoint){} public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations) { operation.ParameterInspectors.Add(new OperationProfilerParameterInspector()); } } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { foreach (ClientOperation operation in clientRuntime.Operations) { operation.ParameterInspectors.Add(new OperationProfilerParameterInspector()); } } } public class OperationProfilerBehaviorExtensionElement : BehaviorExtensionElement { protected override object CreateBehavior() { return new OperationProfilerEndpointBehavior(); } public override Type BehaviorType { get { return typeof(OperationProfilerEndpointBehavior); } } }configuration change for the new behavior
The same can be done at the client side.
Service1Client client = new Service1Client(); client.Endpoint.Behaviors.Add(new OperationProfilerEndpointBehavior());or in configuration like this
No comments:
Post a Comment