Creating an Extraction Rule for VSTS 2008 Web Tests

Extraction rules are essentially for finding data in the HTTP response and placing it in the output context of the web test. There are a few built-in tests, but they mostly focus on the HTML tags themselves and the attributes. In my case I really needed the data between span tags. I think this could probably be done with the existing rules and some regular expressions, but I couldn’t resist the chance to write some code and learn something new.

All you need to do is place the class file in the Test Project and compile it. The rule automatically becomes available to the tests in the project.  Here is my class that finds a span for a given ClientId. It overrides the Execute method of the ExtractionRule base class and attempts to find a span for the given ID. If the span is found, it parses the HTML string to find the content of the span tag.

namespace WebTestDemo

{

    [System.ComponentModel.DisplayName("Span Extractor")]

    public class ExtractSpan : ExtractionRule

    {

        // The name of the desired input field

        private string nameValue;

        public string ClientId

        {

            get { return nameValue; }

            set { nameValue = value; }

        }

 

        public override void Extract(object sender, ExtractionEventArgs e)

        {

            string[] tagTypeFilter = new string[] { "span" };

 

            //Fail the test if nothing is found (this may need to be modified)

            e.Success = false;

 

            if (e.Response.HtmlDocument != null && e.Response.IsHtml)

            {

                try

                {

                    //Find the span tag based on ID. Exception if none found

                    HtmlTag result = e.Response.HtmlDocument.GetFilteredHtmlTags(tagTypeFilter).First(t => string.Equals(t.GetAttributeValueAsString("ID"), this.nameValue, StringComparison.OrdinalIgnoreCase));

 

                    //The span was found (no exception), now find the data

 

                    //Get the location of the ID in the span tag

                    int startPosition = e.Response.BodyString.IndexOf(this.nameValue);

 

                    //Find the position of the data immediately following the closing angle bracket of the span,

                    //  accounting for the > character as well

                    startPosition = e.Response.BodyString.IndexOf(">", startPosition) + 1;

 

                    //Get the position of the closing tag for the span

                    int endPosition = e.Response.BodyString.IndexOf("</span>", startPosition);

 

                    //Fetch the content

                    string content = e.Response.BodyString.Substring(startPosition, endPosition - startPosition);

 

                    //Add the value to the context output. This could just as easily go to a file or a DB

                    // this step is not necessary for the extraction to succeed

                    e.WebTest.Context.Add(this.ContextParameterName, content);

 

                    //Mark the extraction as successful

                    e.Success = true;

                }

                catch (Exception)

                {

                    e.Success = false;

                    e.WebTest.Context.Add(this.ContextParameterName, string.Format("span tag id={0} not found", this.nameValue));

                }

            }

        }

    }

}

Now that I have the class, I need to wire it up to a URL in a web test. Right-click the URL and choose Add Extraction Rule…

AddRuleToTest[1]

I need to set two properties:

  1. Context Parameter Name. This comes from the base ExtractionRule class, and is the name for the data that ends up in the output.
  2. ClientId. This is a custom property from my class. It is the ClientId of the rendered control in the HTML output. The class finds the span with this name and returns the data.

Now when I run the test, if the ClientId I specified was found, it shows up in the Context output after running the test. The Context Parameter Name was “SpanData” in this case:

ExtractionRuleResults[1]

This could be made more robust by not coding specifically for spans. Certainly there could be issues if the tag ID is used more than once or if there is significant nesting of spans within the tag you are trying to find. This code is intended to prove out the concept, it could certainly be made stronger.

One thing I want to mention is that all the code samples I have run across (MSDN included) show the RuleName property as the way to display the extraction rule name in the Visual Studio UI. But under compilation this property comes up as obsolete. I found the answer on Ed Glas’s blog. The obsolete message mentioned using attributes, but this info was not discoverable, so I was quite grateful for that posting to get the syntax correct.

Helpful Links

Must Read VSTS - Testing Related Blogs and Introductory Articles

How to: Create a Custom Extraction Rule

Custom Extraction Rule and Generating a Code Test from VSTS

Posted: Wednesday, August 26, 2009 8:29:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | Performance | Visual Studio | VSTS

Another “Why didn’t someone tell me this earlier” Post

90% of the projects I work on need to send emails, and most clients don’t allow developer SMTP servers floating around their network (for good reason). So a big headache ensues trying to get access to an Exchange or SMTP server somewhere. I have been doing this same dance for years. But today I find a blog post about sending emails without an SMTP server. The .Net calls to SMTP just write the emails out on the file system. It’s just configuration even. So much to know, so little time.

Posted: Wednesday, July 29, 2009 7:12:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.5 | ASP.NET

Casting a Null

Found an interesting tidbit today. There is an ASP.NET page that is using session variables. The user has visited the page, and populated the session. But then the user lingers, and the session times out on a page that is not protected. The user then clicks a button, and the following line of C# code executes:

User foo = (User)Session[“bar”];

So what should happen here? An Exception? That’s what I would have thought. But not true. Since the session has expired, the session variable is now null, and you can cast a null into another data type having a value of null. Just as long as that type is nullable. So the line above is the same as:

User foo = (User)null;

which is perfectly valid.

I got the null reference exception down the line when trying to access a property of foo. So once again, defensive programming is the rule. Check your session variables for null!

Posted: Thursday, July 16, 2009 9:14:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.5 | Strange Problems

LINQ: Selecting in Nested Collections

This took me longer than it should have to figure it out, so I am documenting it for later reuse. The case here is described as such:

I have a collection of person objects, which themselves contain a collection of address objects. I want to find all the addresses in a given city:

public class Address

{

     public string Street { get; set; }

     public string City { get; set; }

     public string Region { get; set; }

     public string Postal { get; set; }

     public AddressType Location { get; set; }

}

 

public class Person

{

     public string Name { get; set; }

     public string ID { get; set; }

     public string Title { get; set; }

     public List<Address> Addresses { get; set; }

}

....

IEnumerable<Address> results = from guy in allPersons

                               from addressResult in guy.Addresses

                               where addressResult City == "London"

                               select addressResult;

I understand this is similar to a join in a SQL statement, but in my case the data does not come from a database but a service where I can't control data selection in that way.

Posted: Tuesday, June 23, 2009 3:07:00 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | Linq

Invalid postback or callback argument - AJAX Control Toolkit

I was working to add some Ajax interactivity to a page that needed some asynchronous workings. Unfortunately, after displaying a ModalPopupExtender and the user clicking the Close button on the “popup”, the page would throw the following exception:

System.ArgumentException occurred
  Message="Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation=\"true\"/> in configuration or <%@ Page EnableEventValidation=\"true\" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation."
  Source="System.Web"
  StackTrace:
       at System.Web.UI.ClientScriptManager.ValidateEvent(String uniqueId, String argument)
  InnerException:

There are lots of explanations out there for this kind of problem, but none of the common answers really fit. The most common answer was to disable event validation. That wasn’t a good answer for me, I don’t think disabling an important security feature because you have complex code is a good solution. The other common answer was to override the render event to register the control posting back with the ScriptManager. This did not work at all for me.

After finding an reading through this post and the comments, I realized the problem was indeed in the code. After the call to ModalPopupExtender.Show(), the original code was re-binding a grid on the page. This order of events was causing the problem. I changed the binding to occur before the call to the ModalPopupExtender by changing which event containing the rebinding call, and the error went away.

Posted: Monday, March 23, 2009 8:46:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.0 | .Net 3.5 | ASP.NET | JavaScript/AJAX

Linq Foray

I’m working on a website with lots of user controls interacting with one another using ASP.NET Ajax using events. So I end up needing to find other controls often, especially within repeaters. Nested controls all over the place. I found this wonderful post about using an extension method to the Controls Collection that flattens the tree and allows for much simpler Linq queries. The extension method adds and All() function which is seriously useful.

Posted: Sunday, March 22, 2009 9:27:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | ASP.NET | JavaScript/AJAX | Linq

Don’t Do This

In ASP.NET, the DataList control renders as a table. Opening a new table in the header and trying to get rows to render just won’t end well. Lots of strange browser behavior should be the tip off that this isn't right.

Posted: Sunday, March 22, 2009 7:48:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.5 | ASP.NET

eBooks on CodePlex

Wriju has a gread roundup of eBooks/guidance available on CodePlex.

Posted: Friday, January 09, 2009 4:01:49 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.0 | .Net 3.5 | Programming | TFS | WCF

Getting Started with WCF and REST

Now that WCF has support for REST in .Net 3.5, it's time to get learning....

WCF REST Starter Kit

A Guide to Designing and Building RESTful Web Services with WCF 3.5

A bunch of screencasts by Aaron Skonnard

WCF and REST from the PDC

Dan Rigsby - REST support in WCF

Posted: Tuesday, November 04, 2008 12:58:09 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | WCF