Dynamic QueryString Correlation: Custom Extraction Rules and WebTest Plug-in


What in the world is Dynamic QueryString Correlation?  Dynamic QueryString values change each time a web page is viewed, they may be a unique session id or some other variable in the web application that is unique to the current user or session.  Creating a Web Test for this type of website can be challenging because after recording the webtest it will be hardcoded with the unique querystring value.  On playback the web application will send a new dynamic value because it's a new session, but the webtest will continue to issue requests with the original hardcoded value and the requests will likely fail. 

A situation similar to this exists with the hidden fields used by ASP.NET but it is more predictable and the webtest engine will automatically apply the HiddenField Extraction Rule when it is encountered.  With dynamic querystring values things are less predictable.  The value could be embedded in a number of html tags or even in client-side script blocks.  A good example of this is in creating webtests for SQL Reporting Services sites.  These sites store session specific information in querystring parameters that are embedded in the page response, particularly in script blocks. 

One of the more common signs that you may be running in to this problem is that the webtest playback works for a short period of time after recording then starts failing.  This could indicate that during the initial playback runs the webtest was using a hard-coded session id in the querystrings that had not yet expired, and the problem was exposed only after that particular session had expired.

It can be very difficult to manually find and apply the necessary extraction rules and databindings so I have created this article to share with you a set of custom extraction rules and a corresponding plug-in that make the task easier.

The Custom Extraction Rules and Plug-in

DynamicQueryStringExtraction: This custom extraction rule is intended to be applied manually in simple cases of this error where the embedded querystring parameter in the web server response appears in the href attribute of an <a> tag.  To use this extraction rule and those that follow create a new class file in your Test Project and add the source below to that file then compile your project.  Add the extraction rule to the request whose response will contain the anchor tag you wish to extract the querystring value from and fill in the rules properties.  I've added some automatic correlation capabilities to this extraction rule that will automatically bind the querystring parameters to the extracted value on any future requests that contain the specified parameter that you can try out, you can turn this on or off via the AutomaticCorrelation property and manipulate how it works via the CorrelateNextRequestOnly property.

Here is the full code for the custom extraction rule: http://blogs.msdn.com/densto/pages/querystring-correlation-custom-extraction-rule-basic.aspx

In many cases the above rule will not be sophisticated enough to fix this type of error as it is often the case that the embedded querystring value will not appear in an <a> tag but in some other tag or a block of client-side script in the page response.  The following two code samples are an extraction rule and webtest plug-in that are intended to be used together.  The extraction rule is a more advanced version of the one above that extracts querystring parameters from the raw response text rather than any specific html tag, and the plug-in will automatically apply this rule to your webtest when it determines it is needed.

After recording your webtest, add the plug-in to your test and run it.  For each request issued by your webtest the plug-in will then parse the last response recieved during the current execution for any occurrences of the current requests url.  For each occurrence found it will then:

  1. Parse out any querystring parameters that appear with that instance of the embedded url and continue processing if the querystring "signature" matches that of the current request (same number of querystring parameter with same names).
  2. For each querystring parameter it will compare the embedded value to the value being used in the current test run, if they are all the same it continues to the next instance of the url in the response text, otherwise it stores the necessary information to alert the user with a MessageBox.

After processing each of the url's embedded in the raw response text from the last response the plug-in will then use a MessageBox to alert the user that they may need to correlate the dynamic value for each one found.  If the user answers yes to the dialog, indicating they would like the plug-in to correlate the value for them the plug-in will then update the value to be used in the current execution, and also save the information in an XmlDocument object loaded with the current webtests xml markup that it is maintaining so that later the updated webtest can be saved.  At the end of the webtest another dialog appears asking the user whether they would like an updated version of this webtest that includes the extraction rules and querystring bindings to automatically correlate the values they've correlated during this run.  At this point the updated webtest is saved in the current execution directory (shown on the dialog) along with a back-up of the original webtest that can be added to the test project and used in future runs.

Here is the full code for the extraction rule used by the plug-in: http://blogs.msdn.com/densto/pages/querystring-correlation-custom-extraction-rule-responsetext.aspx

The full plug-in code can be found here: http://blogs.msdn.com/densto/pages/querystring-correlation-webtest-plug-in.aspx


The goal for this plug-in is that it will work for you on the first run without any needed customization.  I've tested it against some simple sites that put the session id in the pages links, as well as on sql reporting services sites, but I'm sure some of you will find scenarios that I didn't account for.  If you encounter any problems while using this I'd like to hear from you so that I can possibly make updates to the code and keep moving it closer to the point where it will work for everyone on the first run.