Archive for August, 2008

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 »