Wcf parameter validation using IParameterInspector in WCF REST Service

In this blog post we’ll see about a very important feature of the WCF and its extensibility and how it help us to control the behavior of the service. For one of our project, we have developed WCF REST Api to use it in iPhone App. One day we found one bug that one of the wcf service method was not returning the expected output because one input parameter value passed as blank. So we needed to validate parameter before service executed. After some research i have found this IParameterInspector interface which resolved my problem.

Let’s try to understand this powerful feature of wcf. IParameterInspector interface resides in System.ServiceModel.Dispatcher namespace which allows us to inspecting parameters passed in each operation before the call / service is executed and after the response is returned.

This interface contains only two methods:

public interface IParameterInspector
{
	void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState);
	object BeforeCall(string operationName, object[] inputs);
}

AfterCall (string, object[], object, object) :-  Called after client calls are returned and before service responses are sent.

BeforeCall (String, Object[]) :- This method invoked after parameters are deserialized but before they are dispatched to the service operation.

Okay we don’t go too much in theory. So let’s implement the IParameterInspector interface to create a custom parameter inspector which can view and validate the parameters before the call or after the call and see how it throws fault exception if any parameter value not validated.

Here i assume that WCF Service project is already created and let’s create our custom class which implements IParameterInspector interface. Well you can also create separate class library to create custom inspector class and then add this library reference to wcf project.

public class ValidateParameterInspectorAttribute : Attribute, IParameterInspector, IOperationBehavior
{

	public object BeforeCall(string operationName, object[] inputs)
	{
		InputParams.StartValidatingParameters(operationName, inputs);
		return null;
	}

	public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
	{
	}
	
	public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
	{
	}

	public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
	{
		dispatchOperation.ParameterInspectors.Add(this);
	}
}

To attach parameter inspector as an attribute to service operation, i have derived it from “Attribute” class and to add it in service i have implemented “IOperationBehavior” interface. Using “ApplyDispatchBehavior()” method you can add parameter inspector in the DispatchOperation object as shown in above code. Below code snippet shows how you can attach the attribute to an operation.

[ServiceContract]
public interface IStudentService
{
	
	[ValidateParameterInspector]
	[OperationContract]
	[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
			UriTemplate = "/SaveStudentRecord")]
	Response SaveStudentRecord();
	
}

That’s it. No need to do change in web.config file using above approach.

Now when i call SaveStudentRecord() service method from the iPhone app or from the “Advanced Rest Client” then parameter inspector first invoke “BeforeCall()” method, which further call another method of “InputParams” class to validate input parameter as show in below code snippet.

public class InputParams
{
	internal static void StartValidatingParameters(string operationName, object[] inputs)
	{
		var methodParam = inputs.FirstOrDefault() as StudentViewModel;

		if (methodParam != null &&
			string.IsNullOrEmpty(methodParam.StudentName))
		{
			LogErrorMessage(ThrowRequiredValueException(operationName, "StudentName"));
			ThrowFaultException();
		}
		else if (string.IsNullOrEmpty(methodParam.BirthDate))
		{
			LogErrorMessage(ThrowRequiredValueException(operationName, "BirthDate"));
			ThrowFaultException();
		}
		else if (methodParam.RoleID <= 0)
		{
			LogErrorMessage(ThrowRangeException(operationName, "RoleID"));
			ThrowFaultException();
		}
		else if (methodParam.Standard <= 0)
		{
			LogErrorMessage(ThrowRangeException(operationName, "Standard"));
			ThrowFaultException();
		}
		
	}
	
	private static void ThrowFaultException()
	{
		WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
		var wfc = new WebFaultException<Response>(new Response
			(
				false,
				"Oops, Invalid parameter found!"
			), System.Net.HttpStatusCode.OK);
		throw wfc;
	
	}
	
	private static Exception ThrowRangeException(string methodName, string parameterName)
	{
		return new ArgumentException(string.Format("API Name: {0} - Parameter cannot be less than zero.", methodName), parameterName);
	}

	private static Exception ThrowSameValueException(string methodName, string parameter1, string parameter2)
	{
		return new ArgumentException(string.Format("API Name: {0} - Parameter {1} value must not be the same as {2}.", methodName, parameter1, parameter2));
	}

	private static Exception ThrowRequiredValueException(string methodName, string parameterName)
	{
		return new ArgumentNullException(parameterName, string.Format("API Name: {0} - Parameter cannot be blank or null.", methodName));
	}

}

As you see in above code that actual error message would logged for developers’ use and at client side it display only general error message. Well, you can change in above code as per your application architecture and requirement. For demo purpose i have show you only blank value validation and range validation. One important thing is – this is not production-ready code.

And that’s it for now. Hope you enjoyed this post. Leave your comments.