How to: Perform Input Validation in WCF
Applies To
- Microsoft Windows Communication Foundation (WCF) 3.5
- Microsoft .NET Framework 3.5
- Microsoft Visual Studio 2008
Summary
This how-to article shows you how to perform input and data validation on parameters in WCF operations. The article shows you how to create a custom parameter inspector that can be used to validate input on both the server and the client.
Contents
- Objectives
- Overview
- Summary of Steps
- Step 1: Create a Sample WCF Service
- Step 2: Create a Windows Class Library for Parameter Validation
- Step 3: Create a Class That Implements the Validation Logic
- Step 4: Create a Class That Implements a Custom Endpoint Behavior
- Step 5: Create a Class That Implements a Custom Configuration Element
- Step 6: Add the Custom Behavior to the Configuration File
- Step 7: Create an Endpoint Behavior and Map It to Use the Custom Behavior
- Step 8: Configure the Service Endpoint to Use the Endpoint Behavior
- Step 9: Test the Parameter Validator
- Deployment Considerations
- Additional Resources
Objectives
- Learn how to create a custom parameter inspector to validate parameters in the operations of the service.
- Learn how to create a custom endpoint behavior that will consume the parameter inspector.
- Learn how to create a custom configuration element that will allow exposing of the custom endpoint behavior in the configuration file.
Overview
Input and data validation represents one important line of defense in the protection of your WCF application. You should validate all parameters exposed in WCF service operations to protect the service from attack by a malicious client. Conversely, you should also validate all return values received by the client to protect the client from attack by a malicious service.
WCF provides different extensibility points that allow you to customize the WCF runtime behavior by creating custom extensions. Message Inspectors and Parameter Inspectors are two extensibility mechanisms used to gain greater control over the data passing between a client and a service. You should use parameter inspectors for input validation and use message inspectors only when you need to inspect the entire message flowing in and out of a service.
To perform input validation, you will build a .NET class and implement a custom parameter inspector in order to validate parameters on operations in your service. You will then implement a custom endpoint behavior to enable validation on both the client and the service. Finally, you will implement a custom configuration element on the class that allows you to expose the extended custom endpoint behavior in the configuration file of the service or the client.
For the purpose of this how-to article, you will create a WCF Service with wsHttpBinding and host it in IIS.
Summary of Steps
- Step 1: Create a Sample WCF Service
- Step 2: Create a Windows Class Library for Parameter Validation
- Step 3: Create a Class That Implements the Validation Logic
- Step 4: Create a Class That Implements a Custom Endpoint Behavior
- Step 5: Create a Class That Implements a Custom Configuration Element
- Step 6: Add the Custom Behavior to the Configuration File
- Step 7: Create an Endpoint Behavior and Map It to Use the Custom Behavior
- Step 8: Configure the Service Endpoint to Use the Endpoint Behavior
- Step 9: Test the Parameter Validator
Step 1: Create a Sample WCF Service
In this step, you create a WCF service in Visual Studio, hosted in an Internet Information Services (IIS) virtual directory.
In Visual Studio, on the File menu, click New Web Site.
In the New Web Site dialog box, in the Templates section, select WCF Service. Make sure that the Location is set to Http.
In the New Web Site dialog box, set the new Web site address to https://localhost/WCFTestParameterValidation and then click OK.
By default, your WCF service will be configured to use wsHttpBinding binding with message security and Windows Authentication. Verify that your web.config configuration file looks as follows:
… <services> <service name="Service" behaviorConfiguration="ServiceBehavior"> <!-- Service Endpoints --> <endpoint address="" binding="wsHttpBinding" contract="IService"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> …
Step 2: Create a Windows Class Library for Parameter Validation
In this step, you create a Microsoft Windows class library project that will include three classes for the custom parameter validation:
- One class to implement the parameter validation logic
- A second class to implement the endpoint behavior that will use the custom parameter class
- A third class to implement a behavior extension so that the validator will be visible in the service and client configuration files
Perform the following steps:
Open a new instance of Visual Studio, leaving your WCF service solution open.
In the new instance of Visual Studio, on the File menu, click New and then click Project.
Expand Visual C#, click Windows, and then select Class Library.
In the Name field, type MyParameterValidator and then click OK.
In the Solution Explorer, right click References, click Add Reference, click the .NET tab, select System.ServiceModel, and then click OK.
In the Solution Explorer, right-click References, click Add Reference, click the .NET tab, select System.Configuration, and then click OK.
Open the Class1.cs file and rename the class name from Class1 to Validation.
Add the following using statements to the top of the Class1.cs file.
using System.Configuration; using System.ServiceModel; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher;
Step 3: Create a Class That Implements the Validation Logic
In this step, you create a new class, derived from IParameterInspector, to implement the validation logic.
The newly created class has the following characteristics:
- It implements AfterCall() and BeforeCall() methods.
- When used as part of the service, BeforeCall() will be invoked before the parameters are dispatched to the service operation. AfterCall() will be invoked after the service has processed the call and is returning a response to the client. Use BeforeCall() to validate your input parameters and AfterCall() to validate your output parameters.
- When used as part of the client, BeforeCall() will be invoked before calling the service, and AfterCall() before the service's response is dispatched to the client code. Use AfterCall() to validate the response from the service, and BeforeCall() to validate the return from the service.
This example uses simple validation logic to check if the parameter passed to the operation is within the values 1 and 5. If the validation fails, an exception is thrown with the Validation Input Error message.
Perform the following steps:
Open the Class1.cs file and rename the class name from Class1 to Validation. Click Yes in the dialog box that appears.
Add the following using statements to the top of the Validation.cs file:
using System.ServiceModel; using System.ServiceModel.Dispatcher;
Add the following code to implement the AfterCall method in the ValidationParameterInspector class:
public class ValidationParameterInspector : IParameterInspector { public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) { if (operationName == "GetData") { for (int index = 0; index < outputs.Length; index++) { if (index == 0) { // execute the method level validators if (((int)outputs[index] < 0) || ((int)outputs[index] > 5)) throw new FaultException("Your Error Message"); } } } } }
Add the following code to implement the BeforeCall method in the ValidationParameterInspector class:
public class ValidationParameterInspector : IParameterInspector { public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) { … } public object BeforeCall(string operationName, object[] inputs) { if (operationName == "GetData") { for (int index = 0; index < inputs.Length ; index++) { if(index==0) { // execute the method level validators if (((int)inputs[index]<0) || ((int)inputs[index] > 5)) throw new FaultException("Validation Input Error"); } } } return null; } }
Step 4: Create a Class That Implements a Custom Endpoint Behavior
In this step, you create a new class, derived from IEndpointBehavior, that implements a custom endpoint behavior.
The newly created class has the following characteristics:
- It implements ApplyClientBehavior() to add the ValidationParamaterInspector to the client operation and enable client-side validation.
- It implements ApplyDispatchBehavior() to add the ValidationParameterInspector to the dispatch operation and enable service-side validation.
- It verifies that it is enabled in the configuration before adding the ValidationParameterInspector to the client or dispatch run time.
Perform the following step:
Copy the following code snippet and paste it into the Class1.cs file, inside the Validation class that already exists:
class ValidationBehavior : IEndpointBehavior { private bool enabled; #region IEndpointBehavior Members internal ValidationBehavior(bool enabled) { this.enabled = enabled; } public bool Enabled { get { return enabled; } set { enabled = value; } } public void AddBindingParameters(ServiceEndpoint serviceEndpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior( ServiceEndpoint endpoint, ClientRuntime clientRuntime) { //If enable is not true in the config we do not apply the Parameter Inspector if (false == this.enabled) { return; } foreach (ClientOperation clientOperation in clientRuntime.Operations) { clientOperation.ParameterInspectors.Add( new ValidationParameterInspector()); } } public void ApplyDispatchBehavior( ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { //If enable is not true in the config we do not apply the Parameter Inspector if (false == this.enabled) { return; } foreach (DispatchOperation dispatchOperation in endpointDispatcher.DispatchRuntime.Operations) { dispatchOperation.ParameterInspectors.Add( new ValidationParameterInspector()); } } public void Validate(ServiceEndpoint serviceEndpoint) { } #endregion }
Step 5: Create a Class That Implements a Custom Configuration Element
In this step, you create a new class, derived from BehaviorExtensionElement, that implements a custom configuration element.
The newly created class has the following characteristics:
It implements CreateBehavior() to create an instance of the ValidationBehavior class.
It implements BehaviorType() to return the ValidationBehavior type.
This will allow the custom behavior to be exposed in the service or client configuration sections.
It implements ConfigurationProperty to allow the behavior to be enabled or disabled in the WCF configuration files.
Perform the following step:
Copy the below code snippet and paste it into the Class1.cs file, inside the Validation class that already exists:
public class CustomBehaviorSection : BehaviorExtensionElement { private const string EnabledAttributeName = "enabled"; [ConfigurationProperty(EnabledAttributeName, DefaultValue = true, IsRequired = false)] public bool Enabled { get { return (bool)base[EnabledAttributeName]; } set { base[EnabledAttributeName] = value; } } protected override object CreateBehavior() { return new ValidationBehavior(this.Enabled); } public override Type BehaviorType { get { return typeof(ValidationBehavior); } } }
Step 6: Add the Custom Behavior to the Configuration File
In this step, you add the custom behavior to the behavior element extension in the WCF configuration file so that it can be used by the WCF endpoint.
Compile your validation class library solution to create MyClassValidation.dll.
Return to the original instance of Visual Studio that contains your WCF service solution.
Right-click the WCF Web site project and then click Add Reference. Navigate to the folder containing MyClassValidation.dll and then click Add.
Right-click web.config and then click Edit WCF configuration.
If you do not see the Edit WCF Configuration option, on the Tools menu, click WCF Service Configuration Editor. Close the WCF Service Configuration Editor tool that appears. The option should now appear on the web.config context menu.
Expand the Advanced node and the Extensions node, and then click behavior element extensions.
Click New.
In the Name field, type Validator
Select the Type field, click the button that appears to the right, navigate to the folder containing MyClassValidation.dll, and then double-click the dll file.
Double-click the type name MyParamaterValidator. CustomBehaviorSection and then click OK.
In the WCF Configuration Editor, on the File menu, click Save.
Verify that your configuration file contains the following:
<system.serviceModel> ... <extensions> <behaviorExtensions> <add name="Validator" type="MyParamaterValidator. CustomBehaviorSection, MyParamaterValidator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions> ... <system.serviceModel>
Step 7: Create an Endpoint Behavior and Map It to Use the Custom Behavior
In this step, you create an endpoint behavior and map it to the custom behavior created in Step 6.
In the WCF Configuration Editor, expand the Advanced node, right-click Endpoint Behavior, and then click New Endpoint Behavior Configuration.
Select the new behavior and then in the Name field, type MyEndPointBehavior
Click Add, select the Validator custom behavior, and then click Add.
In the WCF Configuration Editor, on the File menu, click Save.
Verify that your configuration file contains the following:
<behaviors> ... <endpointBehaviors> <behavior name="MyEndPointBehavior"> <Validator /> </behavior> </endpointBehaviors> ... </behaviors>
Step 8: Configure the Service Endpoint to Use the Endpoint Behavior
In this step, you configure the service to use the endpoint behavior in order to consume the custom validator.
In the WCF Configuration Editor, expand the Services node, then expand the Service node and then expand Endpoints.
Select the first [Empty Name] node.
In the BehaviorConfiguration field, select MyEndPointBehavior.
In the WCF Configuration Editor, on the file File menu, click Save.
Verify that your configuration file contains the following:
<endpoint address="" behaviorConfiguration="MyEndPointBehavior" binding="wsHttpBinding" contract="IService"> <identity> <dns value="localhost" /> </identity> </endpoint>
Step 9: Test the Parameter Validator
In this step, you create a sample WCF client to test your validator.
Right-click your WCF service solution, click Add, and then click New Project.
In the Add New Project dialog box, in the Templates section, select Windows Forms Application.
In the Name field, type Test Client and then click OK.
Right-click your client project and then click Add Service Reference.
In the Add Service Reference dialog box, set the Address field to https://localhost/WCFTestParameterValidation/Service.svc and then click Go.
Set the Namespace field to WCFTestService and then click OK.
Open the designer for your new Windows form.
Drag a button control into the designer.
Drag a textbox control into the designer.
Double-click the button to show the underlying code.
In the code behind the button, create an instance of the WCF service proxy, and then call the DoWork() method on your WCF service based on the value that is in the textbox control.
When you call the service, your current user security context will automatically be passed to your WCF service.
private void button1_Click(object sender, EventArgs e) { WCFTestService.ServiceClient myService = new WCFTestService.ServiceClient(); MessageBox.Show(myService.GetData(int.Parse(textBox1.Text))); myService.Close(); }
Right-click the client project and then click Set asStartup Project.
Run the client application by pressing F5 or CTRL+F5, and then click the button. In the text box, enter a value and then click the button.
The application will display the message “You entered: value” for the correct value (input between 1 and 5) or a validation error for the incorrect value.
Deployment Considerations
Do not divulge exception errors to clients in production. Instead, develop a fault contract and return it to your client inside the BeforeCall() and AfterCall() methods of the ValidationParameterInspector class. For client-side validation, follow the same steps detailed in this how-to article, but instead use the app.config file of the client consuming the service.
Additional Resources
- For additional information on configuring and extending the run time with behaviors, see Configuring and Extending the Runtime with Behaviors.
- For additional information about the IEndPoint interface, see IEndpointBehavior Interface.
- For additional information about the IParameterInspector interface, see IParameterInspector Interface.
- For additional information about the BehaviorExtensionElement class, see BehaviorExtensionElement Class.