August 10th 2008

Properly using the “references” parameter to the MS Ajax $create statement

Suppose you want to reference a component from another component. The MS Ajax documentation gives the following explanation of the $create function:

Syntax

$create(type, properties, events, references, element);

Arguments

Parameter Description
type The type of the component to create.
properties (Optional) A JSON object that describes the properties and their values.
events (Optional) A JSON object that describes the events and their handlers.
references (Optional) A JSON object that describes the properties that are references to other components.
element (Optional) The DOM element that the component must be attached to.

The documentation doesn’t provide much information, however, on why you should use the references parameter instead of just using the $find method in the initialize event of your component.

When the framework renders $create statements through the scriptmanager,  each script descriptor becomes a $create statement in the page source. These statements are executed by the ajax framework when page_load. In order for a component instance to reference another component instance, the object being referenced has to exist already.  If the $create statement for the object being referenced comes after the referencing component’s $create, an error will occur when the $find method is called.

One way around this is to execute $find every time that the component needs to be referenced. This has performance implications and doesn’t scale well when dealing with collections of components.

Another way around this is to use the MS Ajax Application_load event using code similar to the following:

MyNamespace.MyComponent.prototype = {
 initialize: function() {
  MyNamespace.MyComponent.callBaseMethod(this, 'initialize');

  this._applicationLoadHandler = Function.createDelegate( this, this.applicationLoad );
  Sys.Application.add_load( this._applicationLoadHandler );
  
 },

 applicationLoad: function(sender, e) {
 
  this._componentReference = $find(this._componentReferenceId);
  //Remove the LoadHandler 
  Sys.Application.remove_load( this._applicationLoadHandler );
  this._applicationLoadHandler = null;
 },
 
 set_ComponentReferenceId : function( value ) {
  this._componentReferenceId = value;
 },
  
 get_ComponentReferenceId : function() {
  return this._componentReferenceId;
 }
 // other code
}

This approach is explicit and therefore more clear to other developers who might inherit your code. Additionally for collections of components, this method is an excellent option.

The framework does, however, does provide a way to ensure that when the initialize method is called, the component references have already been set just like other component properties.

If our custom component inherits from AjaxControlToolkit.ExtenderControlBase, we can add the AjaxControlToolkit.ComponentReference attribute to the property declaration

<AjaxControlToolkit.RequiredProperty()> _
<AjaxControlToolkit.ExtenderControlProperty()> _
<IDReferenceProperty()> _
<AjaxControlToolkit.ComponentReference()> _
<AjaxControlToolkit.ClientPropertyName("ComponentReference")> _
Public Property ComponentReferenceId() As String
 Get
  Return GetPropertyValue(Of String)("ComponentReferenceId", String.Empty)
 End Get
 Set(ByVal value As String)
  SetPropertyValue(Of String)("ComponentReferenceId", value)
 End Set
End Property

Note: we also need to change the getter/setter methods in the javascript to:

set_ComponentReference : function( value ) {
  this._componentReference = value;
},
get_ComponentReference : function() {
  return this._componentReference;
}

Before the initialize method is called the framework will now call set_ComponentReference and pass $find(value from the server side property) as the sole parameter.

If you’re not extending from AjaxControlToolkit.ExtenderControlBase, you can perform the same operation by using the SetComponent method in the GetScriptDescriptors method:

Protected Overrides Function GetScriptDescriptors(ByVal targetControl As System.Web.UI.Control) As System.Collections.Generic.IEnumerable(Of System.Web.UI.ScriptDescriptor)
 Dim descriptor As New ScriptBehaviorDescriptor("MyNamespace.MyComponent", targetControl.ClientID)
 descriptor.AddComponentProperty("ComponentReference",Me.ComponentReference)
 ...
 Return New ScriptDescriptor() {descriptor}
End Sub

In either event, the net result should be a statment similar to the following generated by the framework in the page source:

Sys.Application.add_init(function() {
    $create(MyNamespace.MyComponent, {…,”id”:”CustomComponentId”}, null, $find(”RefefencedBehaviorId”), $get(”targetControlId)”));
});

No Comments yet »

August 10th 2008

Binding MS Ajax Extenders to nested Controls

The MS Ajax Extender model encourages us to bind html elements to extender properties via clientId. To help make this more declarative, the ajax control toolkit provides property attributes to do this mapping between server side control property and client side javascript accessor methods:

[IDReferenceProperty(typeof(WebControl))]
[DefaultValue("")]
[ExtenderControlProperty]
[ClientPropertyName("popupElement")]
[ElementReference]
[ExtenderControlProperty]

public string PopupControlID { � }

In this case, the framework will call a method on the javascript extender called “set_popupElement” and pass it the result of $get(”value from PopupControlId on the server side”).

This method works well until you want to bind the extender against elements contained in a different naming container. For example, suppose you create a custom extender to populate a popup panel depending on what link a user clicks upon.

Assume the popup panel control is in fact an asp.net panel. Since panel implements INamingContainer, the custom extender will not locate any elements inside it because the extender’s parent control (the one whose childControls collection it searches) is not the panel itself. Since FindControl() is not recursive, when the extender tries to find the controls inside the panel by Id, it will be unable to locate them.

One limited workaround is to move the extender inside the asp.net panel. This will work until the extender has to resolve controls both inside and outside the popup panel.

Another workaround is to set the element ids in the code behind.

MyExtender.PopupControlId = this.PopupPanel.FindControl(”elementToBindAgainst”);

 this can be quite tedious depending on the number of controls you want to bind against and is less intuitive than the declarative approach.

Assuming the extender inherits from AjaxControlToolkit.ExtenderControlBase, a more flexible method is to override the ResolveControlProperty method as follows:

 public string SearchContainerPaths { get; set; }

  private bool searchControlsInitialized;
  private System.Collections.Generic.List<Control> searchContainers = new System.Collections.Generic.List<Control>();
  protected void ResolveControlProperty(object sender, ResolveControlEventArgs e)
  {
   if (string.IsNullOrEmpty(e.ControlID))
   {
    return;
   }

   if (!this.searchControlsInitialized) //check tosee if we've built the "probe" collection of containers to search
   {
    char[] splitChar = new char[] {’.'};
    string[] controlPaths = this.SearchContainerPaths.Split(new char[] {’,'});
    foreach (string path in controlPaths) {
     string[] subPaths = path.Split(splitChar);
     Control ctl = this.Parent;
     foreach (string controlId in subPaths)
     {
      ctl = ctl.FindControl(controlId);
      if (ctl == null)
      {
       throw new ArgumentException(”Cannot find path:” + path);
      }
     }
     this.searchContainers.Add(ctl);
    }
    searchControlsInitialized = true;
   }
   Control tmpCtl = null;
   foreach (Control control in this.searchContainers)
   {
    tmpCtl = control.FindControl(e.ControlID);
    if (tmpCtl != null)
    {
     e.Control = tmpCtl; //the control is found, set it and exit.
     break;
    }
   }
   if (tmpCtl == null) //unable to find control in map paths, throw an exception.
   {
    throw new ArgumentException(”Cannot find controlId: ” + e.ControlID);
   }
  }

By setting SearchContainerPaths we can now probe for any controls outside the immediate naming container e.g. SearchContainerPaths=”panel1.panel2,modalPanel” will search the controls collection of panel2 (contained in panel1) and the controls collection of modalPanel.

This sample gives an example of this using the modalPopupBehavior and a customExtender to bind the popup panel.

 

 

No Comments yet »

August 10th 2008

Perils of Sys.UI.Component and Update Panels

When writing custom MS Ajax controls, deciding what framework class to inherit from on the client can be tricky. The MS Ajax documentation gives the following explanation of the Sys.UI.Component and it’s associated child classes here:

Client component object types Summary
Components
  • Derive from the Component base class.
  • Typically have no UI representation, such as a timer component that raises events at intervals but is not visible on the page.
  • Have no associated DOM elements.
  • Encapsulate client code that is intended to be reusable across applications.
Behaviors
  • Derive from the Behavior base class, which extends the Component base class.
  • Extend the behavior of DOM elements, such as a watermarking behavior that can be attached to an existing text box.
  • Can create UI elements, although they do not typically modify the basic behavior of the DOM element that they are associated with.
  • If assigned an ID, can be accessed directly from the DOM element through a custom attribute (expando).
  • Do not require an association with another client object, such as a class derived from the Control or Behavior classes.
  • Can reference either a control or a non-control HTML element in their element property.
Controls
  • Derive from the Control base class, which extends the Component base class.
  • Represent a DOM element as a client object, typically changing the original DOM element’s ordinary behavior to provide new functionality. For example, a menu control might read <li> items from a <ul> element as its source data, but not display a bulleted list.
  • Are accessed from the DOM element directly through the control expando.

If the difference between Behaviors and Controls isn’t clear to you, you’re not alone. In fact, depending on the version of microsoft documentation, or their horrific msdn documentation, these terms are used almost interchangeably. Generally, behavior, extender, control all refer to the same thing - some custom code written in javascript and instantiated via $create.

Following the documentation then, if an extender does not have a target control it should inherit from Sys.UI.Component.

Suppose we have a page that’s using update panels and depending on the user action an extender (inheriting from Sys.UI.Component) is written to the page.

When a postback occurs the extender will be rendered to the page again. Now there will be a new extender and an existing extender both with the same id. This will cause a javascript error that’s hard to track down, something like “Behavior with Id:? already exists”.

The original instance of the extender should have been disposed when the update panel framework reloaded the page. Since the extender didn’t have a target element (the core difference between Sys.UI.Component and Sys.UI.Behavior), the framework didn’t know to dispose the extender object when the update panel refreshed its content. 

To work around this, simply change the extender to inherit from Sys.UI.Behavior and giving it a target element. This will ensure that the object is disposed when the target element is disposed when either the update panel framework destroys the target element or the page is unloaded.

No Comments yet »

August 10th 2008

Converting VB to C# while preserving project references and existing solutions

We’ve recently begun converting a tremendous amount of code from VB to C#.  Others have much better postings about the pros and cons of chosing VB or C#.  The web is littered with religious rants from haughty C# developers (although they are in the minority of .net developers) about which managed language is better.

We chose VB originally because it was easier to develop against, it was a language the team was familiar with, and we didn’t have time to ramp both to .net 2.0 and all the quirks of C#. At the time, there were virtually no features of C# that we felt would make our work more efficient.  Over time, however, our team has changed - some of the original developers have moved on and some really smart people with a lot of strong C#/Java experience have joined us. We’ve also had two years to ramp up on .net 2.0 and are now moving on to 3.5 with enthusiasm.  Part of the point in moving to 3.5 is to leverage language features only available in C#.

The tool we selected for conversion is C-Sharpener for VB.Net because it converts projects in total and does symbol comparison on the output.  Minor quirks of the software include the following:

  1. in VB, int(5) means an array with upper-bound 5, but in C# int(5) means an array with 5 elements and upper-bound 4)
  2. a small issue with complex generics- a dictionary whose value was also a generic does not convert properly
  3. embedded resource references in C# require full names including directory path e.g. to access the embedded resource file name “MyResource.txt” in C#, we would need to call assembly.GetManifestResourceStream( “MyResourceFiles.SomeChildDirectory.MyResource.txt” ) as opposed to the seemingly simpler VB assembly.GetManifestResourceStream( “MyResource.txt” ).
  4. namespace statements are parsed by period. “Namespace A.B.C” becomes
    namespace A
    {
        namespace B
        {
            namespace C
            {

Once the project is converted, C-Sharpener gives adds the newly created C# project to your solution with the original project name and “_CS” appended to it.

In order to finish the conversion, we need make changes to unmodified versions solution (.sln file) via text editor.
note: C-Sharpener will change the solution when it runs to add the new C# project so be sure to revert the solution after the conversion.

Rather than go through every project’s references and update them to the GUID of the new project we’d like to simply reuse the GUID. This is relatively easy

  1. Open the source VB project’s vbproj file in a text editor and copy the inner text of the ProjectGuid element.
  2. Open the csproj file of the newly created project in a text editor.
  3. update the AssemblyNamespace and RootNamespace elements by removing the extra “_CS”
  4. Update the <ProjectGuid> element - set the inner text of the element to the inner text of the ProjectGuid from the original vb project.
  5. open all solutions containing the original vb project in a text editor.
    your vb project should be referenced in the file like so:Project(”{ProjectTypeGUID}”) = “MyAssembly”, “..\MyAssembly\MyAssembly.vbproj”, “{MyProjectGUID}”
    EndProject
  6. update the path to the newly created cs projectProject(”{ProjectTypeGUID}”) = “MyAssembly”, “..\MyAssemblyInCSharp\MyAssembly.csproj”, “{MyProjectGUID}”
    EndProject

    note: you’ll need to update the path to the csproj and make sure the GUID following it (MyProjectGUID) is the same as the one you pasted from the VB project.

  7. The ProjectTypeGUID indicates to Visual Studio when it tries to compile your solution what kind of project it is - C#, VB, Cobol etc. for example, one of our solutions contains C#, VB, and web deployment projects. It looks like this:Project(”{F184B08F-C81C-45F6-A57F-5ABD9991F28F}”) = “VBProject”, “..\VBProject\VBProject.vbproj”, “{27509F53-2929-459A-8B1E-E03ADA1D8B36}”
    EndProject

    Project(”{2CFEAB61-6A3B-4EB8-B523-560B4BEEF521}”) = “WebDeploymentProject”, “WebDeploymentProject.wdproj”, “{24F3E583-E313-48D6-92ED-A137AC83BBDB}”
    EndProject

    Project(”{F184B08F-C81C-45F6-A57F-5ABD9991F28F}”) = “VBProject2″, “..\VBProject2\VBProject2.vbproj”, “{C73B5D28-96D6-4B29-B90D-E0E3788F0692}”
    EndProject

    Project(”{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}”) = “CSharpProject”, “..\CSharpProject\CSharpProject.csproj”, “{D20CCA67-387E-4B1F-9232-1EEE1359CD9E}”
    EndProject

    note how the second GUID in each project is unique. The first GUID is the one you need to change to tell the solution that the project is no longer a VB project but a C# one instead. For your project, update ProjectTypeGUID to the C# guid - FAE04EC0-301F-11D3-BF4B-00C04F79EFBC.

 

 

No Comments yet »

August 10th 2008

Interface Segregation Principle, Asp.Net, Generics, Interfaces and Covariance, Oh my!

The interface segregation principle is something most asp.net developers tend to ignore. If I only have one consumer of my business layer (the web/UI layer) why bind against an interface instead of the actual business objects?

Recently at my job we found ourselves answering that question. We have a single code base and strong continuous integration. Binding to UI interfaces seemed to make things “less agile” :). Now that we’re live, however, things have changed. We’re willing to sacrifice the beautiful patterns we’ve held so dear for the pragmatic concerns of performance and scalability.

We analyzed our application for problems and began to work around some of our thornier speed issues by writing custom sql that could leverage vendor specific database features and using the caching features of the asp.net framework.

The problem is that our business entities are too heavy - these custom queries were faster in part because we didn’t need to retrieve all the data necessary to initialize an entity. Additionally, to avoid GC problems, the data we wanted to cache needed to be much “lighter” without references to other objects or data context.

Our web code was now too rigid. It was binding against strongly typed business objects and needed to bind against interfaces to give us the flexibility and control re-use we needed. We therefore adjusted the necessary Asp.net controls that bound to entities to bind to interfaces instead.

A problem arose, however, when we went to bind lists. The problem is called covariance and discussed very well here and compared with JAVA here. Basically, to optimize performance, the .net runtime emits code to strongly type collections. This new type has no ties to the interfaces or inheritance hierarchy of the type that it is templating e.g. If A is the base class of B and C, one cannot pass a List<B> to a method expecting a paramter of type List<A>.

The way around this is actually pretty simple. It’s how most asp.net controls work out of the box. A control’s datasource is simply an object. Only when DataBind() is called is the datasource consumed, and then it’s consumed item by item in the ItemDataBound event where there is no problem casting individual items of a datasource to an interface.

This paradigm works well. Though we can’t cast strongly typed generic lists based we can cast Foo to IFoo as we consume each item for databinding. The result is a more flexible UI with more code re-use and improved performance.

No Comments yet »

August 10th 2008

Hallmarks of great developers

At my current employer we’ve spent a long time trying to refine our hiring process. While the process is by no means ideal, after conducting dozens of interviews a few key indictators of great developers have emerged. While not requirements, the developers we’ve hired who are successful and continue to innovate, improvise, and impress all share these qualities.

  1. Reading books.
    This one sounds simple. One applicant I spoke with said “Books make a good reference but I find online resources better for learning and keeping up with technology”. This misses the point entirely. Books are indeed a great reference - they’re more than just a quick answer to a shortlived technical problem. Books help you avoid bothersome technical hurdles in the first place. Jeff Atwood from coding horror expresses this much better here. My team and I spent almost a year working extensively with javascript and the ASP.Net AJAX framework before we ever read a book on the subject. Not suprisingly we learned more from reading the book than we had from all the online references and tutorials. Granted, we were much more receptive to the author’s ideas because we’d already struggled so much with the technology, but reading this book made us better developers by helping us connect existing dots and drawing new pictures.There are numerous excellent books out there about everything that software developers do. From books that expand your horizons, books that help you write better code, books that give you perspective on the bigger picture, books on patterns and practices ,and even fictional books that reinforce what I love about developing software.Many people go out and buy the bible for the next version of some framework or technology. The version they wish they were using, but never end up reading because it doesn’t apply to their work. People who take an interest in doing what they spend 40+ hours a week better are more likely to do a better job for you.
  2. Subscribe to blogs and follow websites
    Blogs keep you abreast of developments in technology. There are really smart people out there with facinating things to say. Following particular blogs shows you have an interest in the world around you and want to see beyond your immediate perspective.Steve Yegge’s blog is brilliant. It’s also opinionated and ignorant of all things microsoft, but he has a lot of really cogent thoughts. Scott Gu’s blog is an invaluable resource to keep up with Microsoft technologies. For year’s Joel Spolsky has provided original thoughts on a wide variety of topics that software developers share in common. I’m glad these guys (and many others) share what they think because there’s a lot to learn from them.
  3. Work to understand the frameworks that they use
    The following are interview questoins I’ve asked:

    • How does the .net xmlSerializer work?
    • How does declarative databinding in the aspx markup work? e.g. <%# DataBinder.Eval(Container.DataItem,”au_id”) %>

    The questions themselves aren’t perfect judges of a developer’s caliber. They do, however, speak to other concerns- Are they using the framework(s) as designed? Is it all voodoo magic or do they know how it works? Before you can understand the limitations of a technology or framework you have to know how it works. Are dynamic languages better or worse than static languages? There are no right answer here, it depends on what you’re trying to do. Neil Ford (from Thoughtworks) said in a talk once that you should generally understand one level deeper than the the code you’re writing. If you’re using asp.net, how does the asp.net framework work? If you’re using a business layer, how does it retrieve and persist data? If you’re writing web pages, how do HTML, HTTP, and web servers work? Technology choices should be based on evidence and fact; learning how things work is a very basic part of that.

  4. Find technology interesting and exciting in its own right
    Most of my time at work is spent with issues that involve code- developing software that is scalable, secure, and efficient while continually work more efficiently. I probably won’t use the next version of Java (I didn’t use the last one much either). I probably won’t make my living coding Ruby on Rails applications. That doesn’t mean that they don’t have interesting innovations, patterns, or paradigms. I love my job, I love doing my job well. Technologies that help me do my job better help make me better and that’s something to be excited about.

The underlying quality in these traits is passion. People who love developing software, like learning, and want to improve as developers are people that we want to hire.

No Comments yet »

May 27th 2008

Optimize UpdatePanel performance by avoiding unnecessary element disposal

I fought using update panels for a long time. Every time someone demonstrates the MS AJAX framework they skip the amazing features and go right to update panels. They’d say “Look how easy they are to use!”, “They integrate right into the code you have now.”, and my personal favorite, “This is how you can AJAX enabled your website”. I thought they were a heavy solution filled with problems like smartnav has in asp.net 1.1.
The MS AJAX framework is much more than just update panels. There’s more to writing AJAX enabled web sites than wrapping your dynamic content inside update panels. However, there’s something I failed to realize- for what they do, update panels are the best tool for the job. If the goal is to asynchronously update content in a page using the same code used to render the content in the first place, updates panels are it. Less obvious features include:

  • Only the data being refreshed is transmitted from the web server
  • UI code uses the same controls to render synchronously or asynchronously
  • The framework manages the loading of additional javascript and css references
  • The framework only renders update panels that have been triggered for refresh
  • There is a simple and effective way to specify which panels get updated on postback
  • Update panels work almost seamlessly with the other parts of the MS AJAX framework - components, controls, and behaviors

I have now accepted the fact that Microsoft has put more thought, time and money into making update panels better than any homegrown solution.

In the primer Asp.Net AJAX IN ACTION, the authors take great care to explain precisely how update panels work. They describe how the ajax framework creates and disposes components when an update panel’s contents are updated. For every element in the update panel being disposed, the ajax framework checks to see if there are any controls or behaviors bound to the element that needs to be disposed.

Note: any components not bound to elements are not disposed when update panels are refreshed. When the page_unload() event calls the dispose method of the components an error may occur because the DOM state has changed and the components don’t reflect it.

Why bother with object disposal? Why not just replace the innerHTML of the update panel’s div? Julien Lecompte (from Yahoo!) explains a few issues here. Basically, expando attributes on elements cause memory leaks when not disposed properly. Douglas Crockford (also from Yahoo!) describes the basic workaround. Fortunately for us, however, the Microsoft framework does this already in part through the component dispose method.

When the update panel is about to be loaded, the framework doesn’t know which objects need to be disposed. It has to iterate over all the elements about to be destroyed and check for objects to dispose. The following code is from MicrosoftAjaxWebForms.debug.js (comments in code are mine):

function Sys$WebForms$PageRequestManager$_updatePanel(updatePanelElement, rendering) {
	//some code not germane to this post has been omitted here
	//this is where the existing content is disposed
	this._destroyTree(updatePanelElement);
	//and the content is updated
	updatePanelElement.innerHTML = rendering;
}
function Sys$WebForms$PageRequestManager$_destroyTree(element) {
	if (element.nodeType === 1) {
		var childNodes = element.childNodes;
		for (var i = childNodes.length - 1; i >= 0; i--) {
			var node = childNodes[i];
			if (node.nodeType === 1) {
				//if the node has a dispose method, call it
				if (node.dispose && typeof(node.dispose) === “function”) {
					node.dispose();
				}
				//if the node has a sys.ui.control associated with it, call its dispose method
				else if (node.control && typeof(node.control.dispose) === “function”) {
					node.control.dispose();
				}
				//check for sys.ui.behaviors associated with the node and call dispose on each one
				var behaviors = Sys.UI.Behavior.getBehaviors(node);
				for (var j = behaviors.length - 1; j >= 0; j–) {
					behaviors[j].dispose();
				}
				//recurse the contents of this node to do it again
				this._destroyTree(node);
			}
		}
	}
}

If you know there are no objects bound to the content of the update panel, Asp.Net AJAX In Action suggests that you can avoid the performance penalty imposed by the framework’s memory leak prevention. They suggest removing the update panel div from the DOM after the asynchronous result is returned and before the framework applies the result to the DOM. We can use the pageLoading event to do this.

'''
''' Exposes methods to increase update panel performance when the panel contains content without sys.ui.controls associated with it
'''
'''
Public NotInheritable Class UpdatePanelRemoveNodeOnPostback         

	'''
	''' returns string for script to remove the specified control on the client DOM before the page is loaded after an asyncronous postback
	''' this saves the atlas framework from having to traverse the existing dom elements and remove all behaviors, thereby increasing performance
	''' NOTE: THIS CAN ONLY BE USED WHEN THE CONTROL HAS NO CLIENT SIDE CONTROLS ASSOCIATED WITH IT, specifically, as is the case with some of our
	''' gridviews
	'''
	'''

	'''
	'''
	Public Shared Function CreateScriptToRemoveExistingNodeFromUpdatePanelBeforePageLoad(ByVal control As Control) As String
		Return String.Format(System.Globalization.CultureInfo.InvariantCulture, Resources.UpdatePanelRemoveNodeOnPageLoading.Script, control.ClientID, control.ClientID, control.ClientID)
	End Function
End Class

The function references a script included as a resource:

<script type="text/javascript">
	var pageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
	pageRequestManager.add_pageLoading(onPageLoading{0});        

	function onPageLoading{1}(sender, e) {
		var itemToRemove = $('{2}');
		if (itemToRemove != null) {
			itemToRemove.remove();
		}
	}
</script>

One common place I use this is when an update panel contains a gridview. This is an ideal candidate because the amount of html being disposed can be quite large. In the gridview’s container’s preRender event:

Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
	MyBase.OnPreRender(e)
	If GridView.Visible Then
		Dim script As String = UpdatePanelRemoveNodeOnPostback.CreateScriptToRemoveExistingNodeFromUpdatePanelBeforePageLoad(GridView)
		Me.Page.ClientScript.RegisterStartupScript(Me.GetType, "RemoveGridViewPrePostBackLoad", script)
	End If
End Sub

When the update panel is loaded, the javascript code will fire removing the gridview element from the DOM before the disposal code is fired.

2 Comments »

May 27th 2008

Time based Caching in a Load Balanced ASP.Net Application

When using the asp.net application cache a common problem occurs when the application scales from a single web server to a web farm. This problem and more are more broadly discussed here.

One common approach to keep cache items in sync across web servers is use of file dependencies on a central file server. When a depenency file is modified, all web servers in the farm remove the dependent items from their cache.

This works well until one tries to cache an item for a specified duration without a specific file dependency. Consider a web site that shows “recent blog posts”. The list may be constantly changing and although some latency of the data is allowed(hence the caching), the data must always be consistent no matter which web server serves the response.

We can use the same file dependency strategy to keep the cache items in sync between web servers. The “trick” is to produce a hash of the data to be cached and include that information when synchronizing the servers.

If a web server receives a request and does not have the data in its application cache, it must retrieve it.  The server then compares a hash of the data against the contents of a dependency file (unique to that cache item) accessible to all web servers. If the contents of the file are different than the hash generated, the latest results retrieved for the cache item do not match the cache items on other web servers. By replacing the contents of the cache item dependency file with the value of the new hash we can guarantee that the cache items on other web servers will be invalidated and removed.

A sample project demonstrating this is here.

 

No Comments yet »

May 27th 2008

Class Table Inheritance: An Investigation into SQL Performance

Class Table Inheritance is a powerful tool when persisting a strong object oriented business model, but what happens when the data size grows? If we know the type of object we’re selecting, the query is straightforward and performs well:

select
	 base_class.id
	,base_class.sub_type
	,inheriting_class.column1
..
	,inheriting_class.columnn
from
	base_class inner join inheriting_class on base_class.id = inheriting_class.base_class_id

Using multiple tables, requires an inner join to select data and multiple updates to persist it. Outside high volume transaction applications, however, this cost this is negligible.
The problem begins when we need to select a potentially heterogeneous set of records. The longer the inheritance chain and the larger number of sub-classes the less performant our queries will be.
Suppose we have a relatively simple object model as follows:

click the links for scripts to create and populate.

In order to select a set of records “inheriting” from base_class, the business layer or OR/M will generate a query similar to the following (note I’m not selecting all the records, just a subset akin to the filters one would use in a real application):

select
	 base_class.id
	,A.base_class_id
	,B.base_class_id
	,C.base_class_id
	,case when A.base_class_id is not null then 1 when B.base_class_id is not null then 2 when C.base_class_id is not null then 3 end as clazz_
from
	base_class left join inheriting_class_a as A on base_class.id = A.base_class_id
	left join inheriting_class_b as B on base_class.id = B.base_class_id
	left join inheriting_class_c as C on base_class.id = C.base_class_id
where base_class.id % 7 = 1

On average the query takes 700ms on my machine (dual quad-core x64 xp). If we add in our knowledge of the sub-type into the join, the performance does not improve.

select
	 base_class.id
	,A.base_class_id
	,B.base_class_id
	,C.base_class_id
	,case when A.base_class_id is not null then 1 when B.base_class_id is not null then 2 when C.base_class_id is not null then 3 end as clazz_
from
	base_class as base_class left join inheriting_class_a as A on base_class.id = A.base_class_id and base_class.sub_type = 2
	left join inheriting_class_b as B on base_class.id = B.base_class_id and base_class.sub_type = 0
	left join inheriting_class_c as C on base_class.id = C.base_class_id and base_class.sub_type = 1
where base_class.id % 7 = 1

In fact the query execution plan is still the same despite a unique composite index on id and sub_type. The left joins are simply expensive. We need them to return heterogeneous results but the cost has become prohibitive. The longer the inheritance chain and the larger the number of sub-types, the more drastically the performance will degrade beyond this simple example.
One workaround is to perform the expensive outer joins on a smaller subset of date. If we execute the same query using a Common Table Expression and filter the rows before doing the outer joins, the cost decreases by 50% to an average of 371ms.

select
	 base_class.id
	,base_class.sub_type
	,C.base_class_id
	,B.base_class_id
	,C.base_class_id
	,case when A.base_class_id is not null then 1 when B.base_class_id is not null then 2 when C.base_class_id is not null then 3 end as clazz_
from
	base_class as base_class left join inheriting_class_a as C on base_class.id = C.base_class_id
	left join inheriting_class_b as B on base_class.id = B.base_class_id
	left join inheriting_class_c as C on base_class.id = C.base_class_id
where base_class.id % 7 = 1

By comparison, using Single Table inheritance (click links for create and populate scripts), the performace on the following:

	select id, 1 as clazz_
	from sub_class_a
	where id %7 = 1
union all
	select id, 2 as clazz_
	from sub_class_b
	where id %7 = 1
union all
	select id, 3 as clazz_
	from sub_class_c
	where id %7 = 1

is far better than that of the Class Table Inheritance at an average of 140ms. It’s important to note that performance will vary dramatically depending on the size of your data, the “selectiveness” of your where clause and other specifc circumstances.
From the perspective of query performance, Single Table Inheritance is far more efficient than Class Table Inheritance. Within the context of Class Table Inheritance, what is not so obvious is that the cost of returning heterogenous lists or simply not knowing the sub-type at query time can be quite high. Filtering the records (if possible) before applying the outer joins can drastically improve performance.

No Comments yet »

May 27th 2008

Howto: avoid binding the same eventhandler multiple times to an element event in the MS AJAX framework

The Microsoft AJAX $addHandler method is a wrapper to the browser specific implementations of the w3c standard e.g. $addHandler(element, eventName, handler).

Once you’ve bound an event handler to an element, there is no standard way to retrieve the binding information. Javascript frameworks work around this limitation by setting custom properties on the html elements to track handler bindings. As long as handlers are added and removed through the framework things will work as expected with one minor exception. If $addHandler is called twice with the same handler, when the event fires, the handler fires twice.

The Microsoft AJAX framework doesn’t check whether or not a delegate is already bound before binding it a second time, nor does it provide a means to determine what handlers are already bound. The best way to avoid this condition is by following the MS AJAX pattern for binding behaviors and elements. The pattern dictates that elements are “wrapped” in a one-to-one relationship with controls. When a control is initialized it binds element events to its own internal delegates. When other behaviors need to listen for events, they use the event handling architecture for controls and behaviors by binding against the control, not the element. Mike Ormond’s blog provides a good explanation.

Occasionally, you have the problem of adding the same handler multiple times. To work around this we need to know a little more about how the Microsoft framework tracks element event bindings.

When $addHandler is called, Microsoft AJAX adds an expando attribute to the element called “_events”. This is a hash table of the event bindings for the element. Element._events["eventName"] returns an array of delegates bound to the specified element event. The code below simply uses this internal implementation of the MS AJAX framework to avoid duplicate bindings. To use it, simply replace calls to $addHandler and $removeHandler with calls to $addHandlerIfNotDefined and $removeHandlerIfNotDefined.

$handlerDefined = function(elt, eventName, handler) {
	// returns true if an eventHandler has been defined for the given element and the given event
	if ( ( typeof( elt._events ) !== 'object' ) ||
		 ( elt._events === null ) ) {
		return false;
	}
	var cache = elt._events[eventName];
	if ( !(cache instanceof Array ) ) {
		return false;
	} else {
		for (var i=0, l = cache.length; i < l; i+=1) {
				if (cache[i].handler === handler) {
					return true;
				}
		}
	}
}    

$addHandlerIfNotDefined = function(elt, eventName, handler) {
	// ensures the given handler is bound to the given element for the given event
	if ( !$handlerDefined( elt, eventName, handler ) ) {
		$addHandler(elt, eventName, handler);
	}
}    

$removeHandlerIfNotDefined = function(elt, eventName, handler) {
	// ensures the given handler is bound to the given element for the given event
	if ( $handlerDefined( elt, eventName, handler ) ) {
		$removeHandler(elt, eventName, handler);
	}
}

Note: this solution does not handle new instances of anonymous delegates e.g.
$addHandlerIfNotDefined(elt, “onclick”, new Function(evt){some code here});
Since a new anonymous delegate is created each time the handler is added, we would need to compare both the “state” and “code of the delegate for instance equivalence. Determining delegate object equivalence is a difficult thing, the code above compares only delegate instance equivalence.

No Comments yet »

April 21st 2008

Applying for technical jobs? A rough guide

For the last three years I’ve been involved in our company’s development team hiring process.  We’ve defined it, refined it, reworked it, and reworked it again.  We’ve made mistakes and made great hires.  I thought I’d share a few thoughts on the subject which you may find useful. 

For every job posting online, we get 100+ applications.  For every diamond in the rough, there are many more applications we wish we didn’t spend time on.  We only want to hire great developers and have a rule: “no false positives”.  Although we may miss a “diamond in the rough” application, we try to make the time we spend hiring as effective as possible.  Usually we “ding” anyone who:

  1. Doesn’t have a cover letter.
  2. Has numerous spelling errors on their resume or cover letter.
  3. Submitted an application that takes us more than 30 seconds to determine what position you’re applying for and where you’re coming from (e.g. current job is “help desk”, but applying for a programmer position; went to school for art history).  For a better explanation check Rand In Repose’s posting.

So how do you avoid these “dings”?

  1. Have someone proof read your resume
  2. Check out other peoples resumes, e.g.  Resumes That Knock ‘Em Dead and see formats that appear appropriate for the field you work in.
  3. Use a cover letter customized to the position.  Cover Letters That Knock ‘Em Dead has a number of samples to get an idea of the tone and content of what your cover letter should contain.  Make sure to have someone proof read your cover letter before you apply.
  4. Put things on your resume that HR people, recruiters, and automated systems can find.  I don’t mean highlight or boldface all your references to technologies (who started that trend anyways?), use certifications, associations, conferences, and trainings.  HR people aren’t developers.  They don’t know the difference between C# and VB.net or smalltalk and Ruby.  They know keywords they’ve been asked to look for, so make their job easier. By getting certifications, you may not be advancing your education so much as easing the first barrier to entry at any organization - survive the resume screening process.  Certs, conferences, and user groups indicate you’re serious about what you do for a career and advancing yourself professionally. HR people like this.

You’ve submitted your cover letter and resume, and you get a call back.  The usual process is something like this:

  1. HR person/recruiter calls to qualify the application.  They want to sell you on the job - the company, the job itself, the benefits and also determine if this is a good fit for both parties.  They’ll ask the standard personnel questions and more specific questions they’re told to ask. for example
    1. Why are you looking for a job?
    2. When can you start?
    3. What salary are you looking for?
    4. What kind of job are you looking for?
    5. What are your professional goals? -this one is very important. I can’t tell you how many people have applied for developer positions and told me “I want to get into business analysis/project management/developer management” - the job posting was specifically for a software engineer. Why did you apply?
    6. Suppose you and someone have similar resumes. What makes you different?
    7. What books have you read recently?
    8. What blogs do you subscribe to?

    Be prepared for all of these.  The last three are really where we begin to distinguish ambition/character from professional qualifications. They’re good indicators (like education and certification) about what it is you want to do, how motivated you are, and a rough guide to your technical skills.

  2. The technical phone screen.  This person is usually the hiring manager.  His goal is to further qualify you as a potential hire and to help sell you on the job with more details. Expect more technical questions and questions on your experience with certain technologies. 
  3. In person interview.

Hopefully you made it through the screening process and are asked for a personal interview.   Get there early - “if you’re on time, you’re late”.  Once there, relax, use the bathroom, and review your information again- who the company is, what they do, the job description, and what information you’ve given them (resume, cover letter, references etc.).

Steve Yegge has a good description of the general onsite interview process and a whole lot more at “get that job at google.” From his posting:

Every “experienced” interviewer has a set of pet subjects and possibly specific questions that he or she feels is an accurate gauge of a candidate’s abilities. The question sets for any two interviewers can be widely different and even entirely non-overlapping.

 A classic example found everywhere is: Interviewer A always asks about C++ trivia, filesystems, network protocols and discrete math. Interviewer B always asks about Java trivia, design patterns, unit testing, web frameworks, and software project management. For any given candidate with both A and B on the interview loop, A and B are likely to give very different votes. A and B would probably not even hire each other, given a chance, but they both happened to go through interviewer C, who asked them both about data structures, unix utilities, and processes versus threads, and A and B both happened to squeak by.

 That’s almost always what happens when you get an offer from a tech company. You just happened to squeak by. Because of the inherently flawed nature of the interviewing process, it’s highly likely that someone on the loop will be unimpressed with you, even if you are Alan Turing. Especially if you’re Alan Turing, in fact, since it means you obviously don’t know C++.

 The bottom line is, if you go to an interview at any software company, you should plan for the contingency that you might get genuinely unlucky, and wind up with one or more people from your Interview Anti-Loop on your interview loop. If this happens, you will struggle, then be told that you were not a fit at this time, and then you will feel bad. Just as long as you don’t feel meta-bad, everything is OK. You should feel good that you feel bad after this happens, because hey, it means you’re human.

It helps to understand the perspective of the employer on the interview process. Joel Spolsky is an excellent resource on hiring developers.  His book entitled “Smart And Gets Things done“ and blog posting The Guerrilla Guide to Interviewing are essential resources for companies trying to find great talent. From his posting:

You should always try to have at least six people interview each candidate that gets hired, including at least five who would be peers of that candidate (that is, other programmers, not managers). You know the kind of company that just has some salty old manager interview each candidate, and that decision is the only one that matters? These companies don’t have very good people working there. It’s too easy to fake out one interview, especially when a non-programmer interviews a programmer.
 
 If even two of the six interviewers thinks that a person is not worth hiring, don’t hire them. That means you can technically end the “day” of interviews after the first two if the candidate is not going to be hired, which is not a bad idea, but to avoid cruelty you may not want to tell the candidate in advance how many people will be interviewing them. I have heard of companies that allow any interviewer to reject a candidate. This strikes me as a little bit too aggressive; I would probably allow any senior person to reject a candidate but would not reject someone just because one junior person didn’t like them.

Look for passion. Smart people are passionate about the projects they work on. They get very excited talking about the subject. They talk quickly, and get animated. Being passionately negative can be just as good a sign. “My last boss wanted to do everything on VAX computers because it was all he understood. What a dope!” There are far too many people around that can work on something and not really care one way or the other. It’s hard to get people like this motivated about anything.

Bad candidates just don’t care and will not get enthusiastic at all during the interview. A really good sign that a candidate is passionate about something is that when they are talking about it, they will forget for a moment that they are in an interview.

When interviewing we want to give the best impression possible. This is both easier and harder than it may seem.  According to Dave Munger in this post and Malcolm Gladwell in his book Blink(well worth reading), you’ll have about six seconds to make that first impression.  Presenting yourself with confidence and a humble smile will go a very long way to set the right tone for your interview.

Each individual interview will have several distinct sections.

  1. You’ll meet and shake hands.
    A recruiter once told me that at this moment, I should lean forward a little and stand on my toes.  He said it would make me stand up straighter and more importantly it would make me feel a little silly. This would in turn make me smile and relax. When I relaxed, the interviewer would relax.  After interviewing with 4 companies and 20 different people I will tell you, he was exactly right.  As the interviewer of 50+ people for two different companies, I can tell you the opposite is true- the candidates who don’t present themselves well usually have a harder interview as I try to draw them out.
  2. The interviewer will tell you who they are and what they do. 
  3. They’ll ask you some questions. 
    Be polite, be eager, and be positive during all of this. 
  4. Finally they’ll ask you if you have any questions.
    You should always have questions. Questions show you care about the position. It helps draw the interviewer into the conversation.  It’s also one of the only places during the interview process where you’ll get an idea what the job would actually be like.  Questions like: 

    • Who would I be working with? (Are they of your caliber? Are they as motivated as you are?)
    • What would be the first project/team I’d work on here?
    • What would I need to do to meet or exceed expectations after 6 months? (OK this one is a little cheesy, but sometimes effective)
    • Who would be my manager?
    • What feedback loop do you have for my performance?
    • What is the primary focus of the position (you may get a different answer depending on who you ask) - technical? interfacing with users? project management?

So you’re interview is done, and you’re on your way out.  Don’t forget to thank everyone you met, including their “staff”.  Take a moment when you finally get out of there and write down some notes of your impressions (you’ll forget things by the time you get home) what people said, the specifics of the actual job, etc. 

A few final notes:

  • 2 weeks notice to your current employer is standard - if they expect you to leave without notice, it says something about how much they care about people.
  • Always get time to think about the offer- “I have to speak with my family” is a valid answer.  Anyone who goes for the hard sell is sketchy.
  • If things don’t pan out, it’s probably because someone (and it only takes one) thought you weren’t the best fit.  That may be true, it may not, but better no fit than a bad one. 
  • Big companies can afford a longer ramp up time and better training.  Smaller ones are generally looking for you to hit the ground running.  Don’t be upset if someone thought you’d require a little too much training to be useful to them- it’s them, not you :)

No Comments yet »

April 21st 2008

YSlow and ASP.NET - Expires Header - BuildProvider (Part 3 of 3)

For the last part of our quest to enable caching of static content by separating it out into directories by version, we want to provide an easy and intuitive way for developers to reference static content from the code behind. e.g.

Dim linkIcon As New System.Web.UI.WebControls.Image
linkIcon.ImageUrl = StaticContent.Images.rss_gif

Under the covers StaticContent.Images.rss_gif resolves to a method call -StaticContent.PathBuilder.ConvertImageUrl(”rss.gif”) (the method is covered in part 2).
To do this we need a buildProvider (Note: this is not supported in Web Application Projects (WAP) see notes at the end).
The code is mostly written for us on Dave Transom’s excellent post.
The slightly modified code is here.
Now that we have a buildProvider we wire it into the build using the web.config:

<compilation debug="true" strict="true" explicit="true">
	<buildProviders>
		<add extension=".hrefs" type="Savo.Framework.Web.StaticContent.BuildProvider"/>
	</buildProviders>
</compilation>

To configure our BuildProvider create a file with the extension “.hrefs” in your App_Code directory, using some variation on the following:

<?xml version="1.0" encoding="utf-8" ?>
<settings
	namespace=""
	className="StaticContent"
	minDepth="1"
	maxDepth="100"
	lowercaseUrls="true"
	includeExtension="true"
	truncatePathToStartingDepth="true"
	resourceResolutionFormat='StaticContent.PathBuilder.ConvertStaticContentUrl("{0}")'
	directoryNamesToIgnore="StaticContent">
	<files include="\.(gif|jpg|png|css)$" exclude="">
	<folders include="StaticContent" exclude="App_|Bin|\.svn">
</settings>

If you’re using a “Web Application Project”, this method won’t work as per this MS post.  My suggestion is to use a pre-build event (although this has a few extra gotchas) or another framework like slink though I haven’t tried either method.

No Comments yet »

April 21st 2008

YSlow and ASP.NET - Expires Header - Expression Builders (Part 2 of 3)

Continuing our task of caching indefinitely static content by versioning it, we want to build the framework so that instead of code like this:

<asp:image imageurl="~/images/rose.jpg" runat="server" id="image1">

we have this:

<asp:Image id="image1" imageurl="<%$ Image: rose.jpg %>" runat="server"/>

The key difference is that we can dynamically assign where the image path for rose.jpg resolves in the latter case. Specifically, we can resolve to applicationPath/versionX.X.X/Images/rose.jpg (or whatever url scheme meets your fancy).

We need two things. First we create an expressionBuilder object and then tie the custom expressionBuilder into the build. I’m using the VS “WebSite” project, but this should work for “Web Application Projects”.

The following code draws heavily from this post on Dave Reed’s excellent blog infinitiesloop.

Imports System.CodeDom
Imports System.Web         

Namespace StaticContent         

	Public NotInheritable Class PathBuilder         

		Private Shared CssPath As String = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}/StaticContent/{1}/Css/{{0}}", System.Web.HttpContext.Current.Request.ApplicationPath, System.Configuration.ConfigurationManager.AppSettings("versionNumber")))
		Private Shared ImagePath As String = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}/StaticContent/{1}/Images/{{0}}", System.Web.HttpContext.Current.Request.ApplicationPath, System.Configuration.ConfigurationManager.AppSettings("versionNumber")))
		Private Shared JavascriptPath As String = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}/StaticContent/{1}/Javascripts/{{0}}", System.Web.HttpContext.Current.Request.ApplicationPath, System.Configuration.ConfigurationManager.AppSettings("versionNumber")))         

		Public Shared Function ConvertCssUrl(ByVal path As String) As String
			Return String.Format(System.Globalization.CultureInfo.InvariantCulture, CssPath, path)
		End Function         

		Public Shared Function ConvertImageUrl(ByVal path As String) As String
			Return String.Format(System.Globalization.CultureInfo.InvariantCulture, ImagePath, path)
		End Function         

		Public Shared Function ConvertJavascriptUrl(ByVal path As String) As String
			Return String.Format(System.Globalization.CultureInfo.InvariantCulture, JavascriptPath, path)
		End Function         

		Private Sub New()
		End Sub         

	End Class         

	MustInherit Class StaticContentExpressionBuilder
		Inherits Compilation.ExpressionBuilder         

		Protected Shared evaluationExpression As String         

		Protected MustOverride ReadOnly Property StaticContentExpression() As String         

		Public Overrides Function ParseExpression(ByVal expression As String, ByVal propertyType As System.Type, ByVal context As Compilation.ExpressionBuilderContext) As Object
			Return String.Format(System.Globalization.CultureInfo.InvariantCulture, StaticContentExpression, expression)
		End Function         

		Public Overloads Overrides Function GetCodeExpression(ByVal entry As System.Web.UI.BoundPropertyEntry, ByVal parsedData As Object, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As System.CodeDom.CodeExpression
			Return New CodeSnippetExpression(parsedData.ToString())
		End Function         

	End Class         

	<Compilation.ExpressionPrefix("Js")> _
 Class JavascriptExpressionBuilder
		Inherits StaticContentExpressionBuilder         

		Protected Overrides ReadOnly Property StaticContentExpression() As String
			Get
				Return "StaticContent.PathBuilder.ConvertJavascriptUrl( ""{0}"" )"
			End Get
		End Property         

	End Class         

	<Compilation.ExpressionPrefix("Image")> _
	Class ImageExpressionBuilder
		Inherits StaticContentExpressionBuilder         

		Protected Overrides ReadOnly Property StaticContentExpression() As String
			Get
				Return "StaticContent.PathBuilder.ConvertImageUrl( ""{0}"" )"
			End Get
		End Property         

	End Class         

	<Compilation.ExpressionPrefix("Css")> _
	Class CssExpressionBuilder
		Inherits StaticContentExpressionBuilder         

		Protected Overrides ReadOnly Property StaticContentExpression() As String
			Get
				Return "StaticContent.PathBuilder.ConvertCssUrl( ""{0}"" )"
			End Get
		End Property         

	End Class         

End Namespace

I’ve chosen to implement several types of static content (css, images, and js) but that’s just a matter of convenience. Clearly this could all be done with a single expression. Note the reason I have placed the content type specific methods on PathBuilder is that I need to call these methods in part three (code-behind) where accessing the expressionBuilder assemblies would be pretty awkward.

To tie our new expression builders into the build we need to add some entries to the web.config.

<compilation debug="true" strict="true" explicit="true">
	<expressionBuilders>
		<add expressionPrefix="Css" type="StaticContent.CssExpressionBuilder"/>
		<add expressionPrefix="Image" type="StaticContent.ImageExpressionBuilder"/>
		<add expressionPrefix="Js" type="StaticContent.JavascriptExpressionBuilder"/>
	</expressionBuilders>
</compilation>

That’s it. Now we can do things in our markup like:

<asp:image imageurl="Image: rose.jpg" runat="server" id="image1">
<link rel="stylesheet" href="Css: Fonts.css %>" type="text/css" id="FontsCss" runat="server">

the image “rose.jpg” and css file “Fonts.css” will be rendered to the page as urls:
“applicationPath/StaticContent/1.0.0/Images/rose.jpg” and “applicationPath/StaticContent/1.0.0/Css/Fonts.css” respectively.

1 Comment »

April 20th 2008

YSlow and ASP.NET - Concatenating and Minifying Css and Js Resources

In our code we reference several js libraries (prototype, scriptaculous, custom libraries etc.) and we break our css out into several files (layout, fonts, etc.). We encouraged our developers to use whitespace, comments, descriptive names, and separate files to make code as clear as possible. Clear code, however, results in longer download times for web clients.  We wanted to follow the suggestions from the YUI folks to minify and concatenate our resources so that clear code and fast download times could co-exist.

The answer was our automated build. It would have the job of minifying the js and css. It would concatenate the resources together into two files - one for js and one for css.

To use concatenated resources in our code while preserving the ability of developers we work, we changed the the markup section of our master slightly to:

<head runat="server">
	<!-- css -->
	<!--	PLEASE NOTE: CSS and JS ARE COMBINED ON AUTOMATED BUILD
				Please add entries there as necessary!!
	-->
	<link rel="stylesheet" href="Css/Fonts.css" type="text/css" id="FontsCss" runat="server">
	<link rel="stylesheet" href="Css/Structure.css" type="text/css" id="StructureCss" runat="server">
	<link rel="stylesheet" href="Css/Hyperlinks.css;" type="text/css" id="HyperlinksCss" runat="server">
	<link rel="stylesheet" href="Css/Menus.css" type="text/css" id="MenusCss" runat="server">
	<link rel="stylesheet" href="Css/Concatenated.css;" type="text/css" id="ConcatenatedCss" runat="server" visible="false">
	<!-- javascript -->
	<ScriptReference:ScriptRef src="Js/prototype.js" runat="server" ID="UiPrototypeJs">
	<!-- note there are multiple files downloaded after scriptaculous loads, these files should already be included in the concatenated.js if appropriate-->
	<ScriptReference:ScriptRef src="Js/library/scriptaculous.js" runat="server" ID="ScriptaculousJs">
	<ScriptReference:ScriptRef src="Js/library/application.js" runat="server" ID="ApplicationJs">
	<ScriptReference:ScriptRef src="Js/library/Concatenated.js;" runat="server" ID="ConcatenatedScript" Visible="false">
</head>

Note: asp.net doesn’t have a server control for script elements, so we roll our own server control:

Imports System
Imports System.Web.UI       

	Public Class ScriptRef
		Inherits WebControls.Literal       

		Private Const _scriptRefMarkup As String = "<script src="" mce_src=""{0}"" type=""text/javascript""></script>"       

		Public Property Src() As String
			Get
				Return Me.Text
			End Get
			Set(ByVal value As String)
				If Not value Is Nothing Then
					Me.Text = String.Format(Globalization.CultureInfo.InvariantCulture, _scriptRefMarkup, value.Replace("~", System.Web.HttpContext.Current.Request.ApplicationPath))
				End If
			End Set
		End Property       

	End Class

At runtime we can now choose whether to show the css/js files or our concatenated version:

Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
	MyBase.OnInit(e)       

	Dim useConcatenatedJsAndCss As Boolean = False
	If Not String.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings("useConcatenatedJsAndCss")) AndAlso System.Boolean.TryParse(System.Configuration.ConfigurationManager.AppSettings("useConcatenatedJsAndCss"), useConcatenatedJsAndCss) AndAlso useConcatenatedJsAndCss Then
		If useConcatenatedJsAndCss Then
			'NOTE: Whatever we set to visible false here has to be added to the
			'build to be included in the Concatenated css
			FontsCss.Visible = False
			StructureCss.Visible = False
			HyperlinksCss.Visible = False
			MenuCss.Visible = False       

			PrototypeJs.Visible = False
			ScriptaculousJs.Visible = False
			ApplicationJs.Visible = False       

			UiConcatenatedCss.Visible = True
			UiConcatenatedScript.Visible = True
		End If
	End If
End Sub

using the config setting “useConcatenatedJsAndCss”

	<appSettings>
		<add key="useConcatenatedJsAndCss" value="false"/>
	</appSettings>

For minification, we used the YUICompressor. Download it to a place where the build can find it.

<target name="CleanCss">
	<foreach item="File" in="${PathToYourWebSiteBuildOutput}/Css" property="filename">
		<property name="extension" value="${path::get-extension(filename)}">
		<property name="extension2" value="${string::to-lower(extension)}">
		<property name="isCss" value="${string::ends-with(extension2, 'css')}">
		<if test="${isCss}">
			<exec program="java">
				<arg value="-jar">
				<arg value="${YUICompressorPath}">
				<arg value="-o">
				<arg value="${filename}.min">
				<arg value="${filename}">
				<arg value="--warn">
				<arg value="--charset">
				<arg value="Cp1252">
			</exec>
			<move file="${filename}.min" tofile="${filename}" overwrite="true">
		</if>
	</foreach>
</target>       

<target name="CleanJs">
	<foreach item="File" property="filename">
		<in>
			<items>
				<include name="${PathToYourWebSiteBuildOutput}/Javascripts/**/*.js">
			</items>
		</in>
		<do>
			<property name="extension" value="${path::get-extension(filename)}">
			<property name="extension2" value="${string::to-lower(extension)}">
			<property name="isJs" value="${string::ends-with(extension2,'js')}">
			<if test="${isJs}">
				<exec program="java">
					<arg value="-jar">
					<arg value="${YUICompressorPath}">
					<arg value="-o">
					<arg value="${filename}.min">
					<arg value="${filename}">
					<arg value="--preserve-semi">
					<arg value="--charset">
					<arg value="Cp1252">
				</exec>
				<move file="${filename}.min" tofile="${filename}" overwrite="true">
			</if>
		</do>
	</foreach>
</target>

Note: when calling jsmin from the commandline we need to specify the character set for the file we’re compressing or use the default format (ANSI).

For concatenation we can use the build task “concat”. When concatenating files, order is important so we enumerate the files explicitly:

<target name="CombineCss">
	<!-- ordering of concat filesets is nondeterministic, so we concat separately -->
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Css\Concatenated.css" append="false">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Css/Fonts.css">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Css\Concatenated.css" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Css/structure.css">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Css\Concatenated.css" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Css/Hyperlinks.css">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Css\Concatenated.css" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Css/Menus.css">
		</fileset>
	</concat>
</target>     

<target name="CombineJs">
	<!-- ordering of concat filesets is nondeterministic, so we concat separately -->
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/prototype.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/scriptaculous.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/crir.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/builder.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/effects.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/dragdrop.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/controls.js">
		</fileset>
	</concat>
	<concat destfile="${WebSiteStaticContentVersionDirectoryPath}\Javascripts\library\Concatenated.js" append="true">
		<fileset>
			<include name="${WebSiteStaticContentVersionDirectoryPath}/Javascripts/library/slider.js">
		</fileset>
	</concat>
</target>

1 Comment »

April 20th 2008

YSlow and ASP.NET - Expires Header (Part 1 of 3)

At our company there’s a focus on getting our asp.net web application to perform in IE6/7 and FF.  Our site uses javascript and css heavily which results in less than optimal performance.  In an effort to improve performance we took proactive steps by:

  • the size of viewstate and http response on all asp.net requests
  • logging the number of queries used on each http request
  • using the excellent tool YSlow to get insight into the actual content rendered

In future posts I plan to touch upon changes we made in response to these results including minimizing our javascript and css files with YUICompressor and concatenating the results to reduce the number of http requests through our continuous integration process.

The specific challenge I hope to illustrate concerns the default asp.net http headers for content expiration.  By default, asp.net and IIS serve resources with “Cache-Control: private”.  When you close your browser (or the current tab) the content may be cached (depending on your browser (FF and IE6/7 each handle this differently). When the user returns to your site he will either re-request the file and receive an HTTP 304 (”not modified since”) response or download the entire file again. 

In the case where your site has lots of images, js, or css files, you can end up issuing a lot of needless http requests for recurring users.  If instead you were able to set the http cache header to something in the far future, then the browser wouldn’t request the file in the first place.  Scott Hanselman has a good discussion of this behavior here.

In order to cache items at the client you need a way to version them e.g. “~/images/logo.jpg” becomes “v1.0.0/images/logo.jpg”. This way when the resources change they have new paths. These new paths are served up in your markup- the img.src attribute is now different than anything in cache and the browser must therefore request the new version (whose expiration header is also set to a far future date).

The catch is that while asp.net uses the ResolveUrl method and natively changes “~/images/logo.jpg” to “/myapplication/images/logo.jpg”, there is no such mechanism built into the framework to make it translate “~/images/logo.jpg” to “/myapplication/v1.0.0/images/logo.jpg”.

This is a fun problem to solve. It has two parts.

First we must create a framework so that static content can be served easily from the markup by substituting “~/images/logo.jpg” for “<%$ Images: logo.jpg %>”. 

Part 2 will be addressed using expressionBuilders  

Secondly we need to create the framework so that in the code behind, we can replace img.url = “~/images/logo.jpg” with img.url = StaticContent.images.logo_jpg.

Part 3 will be addressed using a build provider.

Both parts will require changes to our build process not covered here.  The continuous integration process should include in its build archive a directory of the static content named by the version number (e.g. v1.0.0) and updating a application configuration property with the specific version so that the application can reference the static content directory properly. 

The Continuous Integration changes will not be covered here because they are very specific to one’s own continuous integration process.  We currently use nant with xmlPreprocess to generate our configuration files for each version and environment (prod, dev, qa, etc.), but there are a ton of ways to do this, all outside of asp.net. Using a small ruby script we generate an additional master settings file to incorporate the latest version number in the master configuration.

No Comments yet »

April 20th 2008

What I wish I knew about Service Broker before I started using it

My current work involves asyncronous communication between multiple servers. Servers in the web farm submit jobs for processing by various backend server farms. Over time our implementation evolved from a simple stored procedure call that polled a table to a much more scalable and fault tolerant MSMQ implementation.

We moved to MSMQ because polling SQL Server tables leads to locking issues with multiple pollers and larger data sets.  Unfortunately, the move to MSMQ separated messages from data, requiring complicated logic to simulate distrubuted transactions across queues and the database. We moved to SQL Service Broker because it is designed to handle multiple pollers, utilizes t-sql,and calls are made inside the current t-sql transaction.

Unfortunately the documentation for Service Broker isn’t all that intuitive and the Microsoft tools (Sql Management Studio in particular) don’t really make things easier. Learning about Service Broker takes time and a healthy dose of experimentation.  Our implementation has been live now for several months and is working well.

Here are a few things we learned along the way:

  • you can see what messages are in a queue by selecting from it - select * from myQueue.
  • the system views sys.service_queues and sys.transmission_queue are your friends. If messages are sent but don’t show up in the queue, check the reason column of the transmission queue.  Most of the time it is because the database master key permissions aren’t set correctly, particularly if the database has been restored. 
  • permissions need to be granted on queues and services to send and receive from them:
    --Grant the user access to the service
    GRANT SEND ON SERVICE::[Your_Service_Name] TO [domain\john.doe] ;
    –Grant the user send rights
    GRANT RECEIVE ON [Your_Queue_Name] TO [domain\john.doe] ;
    –Grant the user receive rights
    GRANT SEND ON [Your_Queue_Name] TO [domain\john.doe] ;
  • when using Activation on queues the procedure actions are included in the current transaction/
  • sending/receiving messages are included in the current transaction.
  • sql management studio does not script broker objects “naturally” - when you script database objects through the UI, service broker objects aren’t included. When you script service broker objects, permissions aren’t included
  • Alter database your_database set new_broker

    will clear all your queues

  • messages in queues are encrypted by default. All messages are hex encoded.
  • if you use a common data store for each endpoint, keep messages as terse as possible. The actual content of the messages is less important than the message itself. If you need additional data, you can retrieve it from the database.

Service Broker has more features than any standard user is likely to encounter.  Asyncronous symptoms can be complicated; building a secure, scalable, fault tolerant system takes a lot of forethought.  Until Microsoft better integrates its product we have blogs, technical articles, forums, etc. to help augment the existing information. Good luck.

No Comments yet »

April 20th 2008

T-SQL Split - An xml based approach

When we select information from our database we have to be careful to filter only results that the user has access to, e.g. an user has access to user information in a fixed list of departments:

Select * from Employee where department_id in (1,3,6)

The problem is comes when we try to parameterize our query because T-SQL requires a parameter for each item in the “IN” clause.  When we use our OR/M (nHibernate) and the setParameterList method, it creates a query like this:

sp_executeSql(n'Select * from Employee where department_id in (@p0,@p1,@p2)',
'@p0 int, @p1 int, @p2 int',
@p0=1,@p1=3,@p2=6);

This has a few issues:

  1. As the list size increases, query performance degrades due to the number of parameters.
  2. We risk throwing a “Too many parameters were provided in this RPC request. The maximum is 2100″ error depending on the number of items in the list(s) the query uses.
  3. These queries cannot be cached effectively because of the variations in parameters.

We considered building a list of comma delimited ids, passing that to SQL as an nvarchar parameter, and using a user defined function like this:

Select * from SomeTable where id in (dbo.fnSplit(@ids))

After some investigation, however, we found no standard way to implement the fnSplit function. Everybody has their own version optimized for list size, ordering, and format.

Instead we serialized the list to xml (pretty easy in.net) and deserialized it using:

CREATE FUNCTION [dbo].[fn_SplitIntsFromXmlNoPrimaryKey](@input varchar(max))
RETURNS @retArray TABLE (id int)
AS
BEGIN
	DECLARE @xml xml
	SET @xml = @input
	insert into @retArray
	SELECT   T.id.value(’.', ‘int’) AS id
	FROM @xml.nodes(’/ArrayOfInt/int’) T(id)
	RETURN
END
select * from [dbo].[fn_SplitIntsFromXmlNoPrimaryKey] (
‘
  33
  72
  74
  76
  78
  80
80
 ‘)

F