OdeToCode IC Logo

Recreational Debugging

Thursday, March 30, 2006 by scott

Eran Sandler runs a great ”Advanced .NET Debugging Blog”. In his recent post “Ambiguous match found in a Web Control - a Possible Bug”, Eran debugs the ASP.NET compiler to find the cause of an error message.

Eran could have fixed the ambiguous match error by changing some code and moving on with life, but it’s hard to pass up a good mystery. It’s fun to figure out why someone else’s code makes our code behave the way it does.

Here is a recent mystery I ran across: why does the following code invoke my workflow’s constructor twice?

WorkflowRuntime runtime = new WorkflowRuntime();
// ...
WorkflowInstance instance;
instance = runtime.CreateWorkflow(
typeof(MyWorkflow));

The obvious first step is to drop a breakpoint in the constructor of MyWorkflow and look at the call stack (Ctrl+Alt+C).

console2.exe!PureCode.MyWorkflow.MyWorkflow() Line 12   
[External Code]    
console2.exe!chapter2_Host.Program.Main() Line 21 + 0x5 bytes

Unfortunately, [External Code] doesn’t tell us anything about where these calls are coming from. This is common when reflection is involved, like when using Activator.CreateInstance.

There are several viable approaches to unravel the mystery, but let’s try the SOS approach. First, we “enable unmanaged code debugging” in the project Debug properties, and then rerun the test harness. When execution stops on the breakpoint in the constructor, switch to the Immediate Window (Ctrl+Alt+I). Now we can load SOS, and look at the call stack with !clrstack.

.load sos
extension C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded
!clrstack
PDB symbol for mscorwks.dll not loaded
OS Thread Id: 0x570 (1392)

PureCode.MyWorkflow..ctor()
[GCFrame: 0012ef5c]
[GCFrame: 0012f040]
[HelperMethodFrame_2OBJ: 0012f05c] System.RuntimeTypeHandle.CreateInstance(...)
System.RuntimeType.CreateInstanceSlow(...)
System.RuntimeType.CreateInstanceImpl(...)
System.Activator.CreateInstance(...)
System.Workflow.Runtime.WorkflowDefinitionDispenser.GetRootActivity(...)
System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(...)
System.Workflow.Runtime.WorkflowRuntime.Load(...)
System.Workflow.Runtime.WorkflowRuntime.GetWorkflowExecutor(...)
System.Workflow.Runtime.WorkflowRuntime.InternalCreateWorkflow(...)
System.Workflow.Runtime.WorkflowRuntime.CreateWorkflow(...)
console2.Program.Main()

The superior stack trace produced by SOS reveals the workflow is instantiated from a method by the name of GetRootActivity. The second time the breakpoints is hit, !clrstack reveals InitializeExecutor as the method calling CreateInstance.

Armed with this bit of knowledge, it’s easy to use Reflector to see what is happening. The very first time the workflow runtime instantiates any given workflow Type, it creates the workflow twice. The runtime passes the first instance through a validation method to ensure the workflow is properly assembled (each activity in a workflow can define custom validations to ensure a proper configuration). The runtime tucks the validated object into a cache, so the runtime will know this workflow Type is “valid” for the duration of the AppDomain. After the first instantiation then, it can skip this validation step. The runtime only creates two instances the first time it sees a given Type.

Another curiosity solved.

Authoring Workflows

Monday, March 27, 2006 by scott

My latest OdeToCode article, Authoring Workflows, looks at how XAML, XOML, partial classes, and compilers all work together in Windows Workflow.

I appreciate any comments, suggestions, and other feedback about the article.

ASP.NET Event Validation and “Invalid Callback Or Postback Argument” : Part II

Wednesday, March 22, 2006 by scott

In the last post we looked at the job event validation performs, and how we can trigger a validation error with some innocent JavaScript. If we receive exceptions because of event validation, we have to disable the feature, or learn how to work with the event validation.

Disable Event Validation

Pros: Easy to do
Cons: Less secure

Bertrand Le Roy wrote a post back in 2004: “Please, please, please, learn about injection attacks!”. Event validation is a feature designed to help prevent injection attacks (of course it can't prevent attacks all by itself).

We can disable event validation for an entire site in the web.config file.

<system.web>
   <
pages enableEventValidation="false"/>
</
system.web>

Alternatively, we can disable validation for a single page.

<%@ Page EnableEventValidation="false" ... %>

Register For Event Validation

Pros: Feel validated
Cons: We need to register all the legal post values before the page is sent to the client - this isn't always possible or practical

When we last left our application, we had a DropDownList with three legal values: “1”, “2”, or “3”. The problem was that client side script was adding a 4th option: “4”. If the user selected the 4th option and posted the form to the server, the server would throw an exception because it didn’t know “4” was a legal value.

The key to passing validation is to let ASP.NET know the value “4” is legal with the RegisterForEventValidation method of the ClientScriptManager class.

RegisterForEventValidation must be called during the rendering phase, so we need to override a Render method. We could start by overriding the Render method of our web form. Plug the following code right below the Page_Load method from the previous post.

protected override void Render(HtmlTextWriter writer)
{
   ClientScript.RegisterForEventValidation(
         _recipeList.UniqueID,
        
"4"
      );

  
base.Render(writer);
}

Remember event validation works by combining the hash of a control’s UniqueID property and a hash of each legal value for that control. The RegisterForEventValidation method accepts both of the calculation inputs as parameters. The method stores the result in a dictionary, and the page adds saves the dictionary as a hidden field on the client.

Adding the RegisterForEventValidation responsibility to the Page class is less than ideal, as the web form suddenly has to know about the DropDownList and its event validation problems. An alternate solution would be to build our own control.

using System;
using System.Web.UI.WebControls;
using System.Web.UI;

namespace OdeToCode.Web.UI.Controls
{
   [
SupportsEventValidation]
  
public class DynamicDropDownList : DropDownList
   {
      
protected override void Render(System.Web.UI.HtmlTextWriter writer)
      {
         Page.ClientScript.RegisterForEventValidation(
              
this.UniqueID,
              
"4"
            );
        
base.Render(writer);
      }
   }
}

A crucial step in the code is to add the SupportsEventValidation attribute to the class. If this attribute is not present, all the RegisterForEventValidation work is in vain. The runtime does not validate events for controls that do not have the SupportsEventValidation attribute present, nor does the runtime does look at the custom attributes of the control’s base class. The table of controls supporting event validation that appeared in the last post was output by a simple program that looped through all the Types in the System.Web assembly looking for the SupportsEventValidationAttribute.

In our example, we knew we only had one additional legal value – the value “4”. We need to call RegisterForEventValidation for every legal value the control might postback. This raises a couple issues because we may not know all of the legal values the control can take. AJAX might populate the control with values from a web service call that is bridged to a third party. Another issue is that the number of legal values might be extremely large.

Unfortunately, ASP.NET doesn’t expose a property to disable event validation for a single control – this would be a nice feature to have. However, if we create a custom control and leave off the SupportsEventValidation attribute, we’ll effectively disable event validation for instances of that class.

ASP.NET Event Validation and “Invalid Callback Or Postback Argument” : Part I

Tuesday, March 21, 2006 by scott

ASP.NET 2.0 added a feature called event validation. Event validation checks the incoming values in a POST to ensure the values are known, good values. If the runtime sees a value it doesn’t know about, it throws an exception.

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.

The error message is a bit wierd and could use some editing, but if someone is trying to attack the application by spoofing a postback, the event validation exception is a good thing. Event validation can help prevent injection attacks from malicious users who are trying to POST data that doesn’t belong.

If we see this exception during the normal execution of an application, the exception is a bad thing. Let’s look at one scenario where the exception can occur after a legitimate postback, and talk about the implementation of event validation. A future post will discuss possible solutions.

Cause

Imagine we’ve been given the task of writing a web form with a DropDownList, and the DropDownList contains three selections.

<h3>Pick Your Favorite Recipe</h3>
<
asp:DropDownList runat="server" ID="_recipeList">
    <asp:ListItem Value="1">
        Amy's Wasabi Encrusted Tuna
    
</asp:ListItem>
    <asp:ListItem Value="2">
        Big Al's Five Bean Burrito
    
</asp:ListItem>
    <asp:ListItem Value="3">
        Scott's Chocolate Carmel Cheesecake Cookies
    
</asp:ListItem>
</
asp:DropDownList>  

Now, it’s a fairly common scenario for client script to populate the contents of a drop down based upon the value of some other control on the page. For example, a list of states may appear after the user selects a specific country. Let’s simulate that scenario by registering some JavaScript which adds a 4th option to the list.

protected void Page_Load(object sender, EventArgs e)
{
   ClientScript.RegisterStartupScript(
         GetType(),
        
"AddToList",
         script.Replace(
"{_recipeListID}", _recipeList.ClientID),
        
true
      );
}

string script =
  
@"      
     var d = document.getElementById('{_recipeListID}');
     d.options[3] = new Option('George\'s Recipe For Disaster', '4');
   "
;

As long as the user selects recipe 1, 2, or 3, the form will postback without errors. If the user selects option 4, George's Recipe For Disaster, the runtime throws an event validation exception. Disaster indeed!

When ASP.NET rendered the DropDownList it recorded all the possible postback values for the control, It does so by looping through the 3 available ListItems and recording each value. When I say “recorded”, I mean for each item in the list the runtime takes a hash of the control’s UniqueID property, and a hash of the ListItem’s Value property, and XORs the two hash values together. The result of this computation is kept in a list with other allowable hashed values, and the list persists itself as a hidden field in the page.

<input type="hidden"
       name="__EVENTVALIDATION"
       id="__EVENTVALIDATION"
       value="/wEWBQKGg9abDQKd9sHMBgKc9s........"
/>

If the user selects George's Recipe, the browser posts back with a value of “4” for the DropDownList. The runtime will perform the same calculation described earlier: hash(_recipieList.UniqueID XOR hash(“4”)). The runtime will try to find the result of this calculation in the list of allowable values de-serialized from the __EVENTVALIDATION field. The runtime won’t find this value, and will sound the alarm by throwing an exception.

To summarize: the runtime threw an exception because the browser posted a value of “4” for the DropDownList. The runtime thinks the only allowable values are “1”, “2”, and “3”. We added the value “4” as an option using client-side script, so ASP.NET did not know it was legal. ASP.NET calculates the allowable postback values at the last possible moment (inside the Render method of the control).

Just for reference, the following controls support event validation. I’ll provide details on how to know if a control validates events in the next post.

HtmlAnchor HtmlButton HtmlInputButton
HtmlInputCheckBox HtmlInputHidden HtmlInputImage
HtmlInputText HtmlInputPassword HtmlInputRadioButton
HtmlInputReset HtmlInputSubmit HtmlSelect
HtmlTextArea BulletedList Button
Calendar CheckBox Table
ChildTable WizardChildTable DataControlButton
ImageButton DataControlImageButton LinkButton
DataControlLinkButton DataControlPagerLinkButton DataGridLinkButton
DetailsView DropDownList FormView
GridView HiddenField ImageMap
LayoutTable ListBox Menu
PagerTable RadioButton RadioButtonList
TextBox TreeView WizardDefaultInnerTable
CatalogZone ConnectionsZone EditorZone
WebPartZone ZoneButton ZoneLinkButton

Using ASP.NET 2.0 to Streamline Web Application Development

Friday, March 17, 2006 by scott

Microsoft released a curious case study yesterday: “Using ASP.NET 2.0 to Streamline Web Application Development”. (Be aware that if you go to read this document, it is a case study. The document is 100% buzzword complaint and strategically aligned to leverage 80% of your existing infrastructure for a 120% ROI over 2 years).

First, the background section describes the problem Microsoft Human Resource IT was experiencing.

Because of this lack of a standardized architecture and design between applications, HRIT experienced increased costs in application maintenance. For example, HRIT recently spent several thousand dollars over a three-month period to update the privacy statements throughout the HRIT application space. This lack of standardization did not only cost HRIT monetarily, but also in lost productivity.

Reading the problem description you can almost feel the solution jumping out of the page.

The HRIT architecture team determined that it could use the master pages available in ASP.NET 2.0 (described in the "Master Pages" section later in this paper) to create a shell application on which to base all new Web applications in the HRIT application space.

Master pages to the rescue! The description makes the solution sounds as if the master pages are bundled into a Visual Studio Project template. All a developer needs to do is create a new web project with the template, and all the master pages, images, and other common goo appears.

The question is what happens when someone wants to change a master page? A project template is only a starting point and can clone the master page into any number of applications. Since the master pages do not live inside some common area or shared repository, someone needs to apply updated master pages to each application.

Right?

Instead of having to update each individual Web application, HRIT must update only Shell Assemblies to have the legal disclaimer updated on every Web application that is based on Shell Assemblies. The foundation of the shell itself is the master pages available in ASP.NET 2.0.

Here is where the case study lost me. It doesn’t sound as if the solution was a project template as much as a shared class library. I wish the case study went into more detail on how the team built the application, because people are looking for techniques to reuse master pages without resorting to virtual directory tricks. Unfortunately, the study confused and misused a number of technical terms.

My guess is the HRIT solution either uses vdir tricks, or creates an empty master page that is built entirely with code. The code could live in a shared assembly. One of the sticking points with master pages is that the MasterPageFile property of a page requires, well, a file. It would be nice if you could set the master page of a form to a compiled type in a referenced assembly. I can also imagine using the VirtualPathProvider to pull a master page out of a shared assembly's resources, but I'm also pretty sure this would break the designer.

Boundaries Are Explicit Because Iteration Kills

Thursday, March 16, 2006 by scott

Growing up with C++, I’ve always expected software to have a strong domain model. If I had grown up with ADO Recordsets or ADO.NET DataSets, perhaps I’d have a different perspective on software, but my initial reaction to the Recordset was bewilderment at an object chocked full of data and no behaviors. I can see both sides of the coin now, and I think both approaches have their advantages in different scenarios. I still prefer the domain model. I do wonder how these models will evolve over the next few years as technologies like DLINQ arrive and continue the push towards abstracting away the database as a minor detail.

Here is some code that works wonderfully well.

BizObject b = new BizObject(/*...*/);

for(int i = 0; i < b.Count; i++)
{
   SomeOtherObject s = b.GetSomeChildObject();
  
  
for(int j = 0; j < s.Count; j++)
   {
      s.UpdateSomeValue();
   }
}

Well, the code works wonderfully well as long as SomeOtherObject is in the same process. As soon as SomeOtherObject becomes a proxy to a remote object, end-users feel the pain of an O(N2) operation carried out by traversing protocol stacks, security boundaries, and network routers. Thus, the SOA tenet arose that boundaries are explicit, and location transparency is a pipedream.

If boundaries are explicit, perhaps database boundaries should be explicit as well. Even though database servers are typically on our side of the firewall, if SomeObject.UpdateValue() is a database roundtrip, the application performance is in a world of hurt.

I’m wondering how to avoid this problem before an application gets into load testing. Static code analysis? Perhaps require the method to be invoked with a different operator? (SomeObject->UpdateValue())? I think -> is a nice indication that the call could possible travel out of process….

Perhaps I'm thinking crazy, or perhaps some dark part of me misses C++ syntax.

ASP.NET in Your Ear

Tuesday, March 14, 2006 by scott

Saturday was a beautiful, sunny day in Washington D.C. Unfortunately, I spent the morning working in the infamous Watergate building, but did get a chance to navigate through the pedestrian traffic at noon and meet Sir Wally McClure for lunch.

Wally is a genuinely funny, smart, and friendly guy. His personality shines through during his ASP.NET Podcast, and makes the show an enjoyable listen. Wally asked me to do a quick interview, and I obliged. He posted the show late Sunday evening. I’ve been dubbed the godfather of the “world needs more Wally” meme that is all the rage.