Fluent.Interface


Javascript Templating within ASP.NET

ASP.NET has rich support for calling AJAX web services, but is usually ignored in preference for a simpler UpdatePanel implementation.

The UpdatePanel is great because it enables developers to slice up their existing pages, and introduce AJAX functionality without significantly changing their post-back logic.  It does however send back all the form variables + ViewState for that page.  It the receives HTML content blocks from the server which is dynamically renders on the client.

But when rendering a data list of objects on a page, you could consider web services:

[WebService(Namespace = "ns")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[
ScriptService]
public class ArticleWebService : System.Web.Services.WebService
{
 
[WebMethod]
  
public List<ArticleDto> GetByName(string name) {
    return null; // TODO: Return list
  }
}

This web service is referenced in the script manager on an ASP.NET client page.

<asp:ScriptManager ID="scriptManager" runat="server" >
  <Services>
    <asp:ServiceReference path="~/services/ArticleWebService.asmx" />
  </Services>
</asp:ScriptManager>

Over the wire the web service call formats objects using JSON format, which ensures a compact and efficient delivery of information.  A list of client-side javascript objects can then be passed onto a templating library which when combined with an in-line template can render HTML to the browser.  I evaluated the following:

  1. JSONT – Transform JSON into text using XSLT style nested rules.
  2. ZPARSE – Lightweight and extensible similar to TrimPath.
  3. FOO Framework – Like ZParse from Rizqi, but Depends on Prototype (1.5+).

They all have their strengths and weakness.  I prefer to minimize the number of AJAX frameworks, and prefer flexible syntax of ZParse (you can customize your parser).  Rich Strahl in his recent What’s Ailing ASP.NET Web Forms post consider’s prototype to be a more well-rounded library, but it requires some tweaks and doesn’t handle character escaping the same way as AJAX does.

The FOO framework is neat in-so-far it annotates in-line HTML but it is much slower (as it iterates over every node with the DOM every time it renders a page).  The alternative approach with JSONT or ZPARSE is to place the template within a hidden textarea control eg:

<!-- Declare the template inside a text area, so we can interegate the .value -->
<textarea id="zparseTemplate" style="display:none">
<!--:foreach a in articles:-->
<div class="wof special-wof">
<h3>
<a href="#" title="{$a.Headline}">{$a.Headline}</a>
</h3>
<p class="cfix">{$a.Abstract}</p>
</div>
<!--:/foreach:-->
</textarea>

The using ZParse the template could be loaded up with a series of ‘articles’ that were loaded from the web service callback.

var parser = new ZParse(Implementation);
var template = $get('zparseTemplate').value;
parser.parse(template);
var content = parser.process(articles);
$get('zparseBlock').innerHTML = content; 
 

A number of factors need to be considered when option for AJAX+Templating for rendering content like this.

  • Content won’t be visible for SEO purposes.
  • Best for dynamic content, where a page would otherwise be cached.
  • Performance test: 2 small hits may prove less scaleable then 1 bigger hit.

I will be following up with an article on Caching.

Advertisements

Google release chart API in their ‘off’ time

Google has just rolled out an impressive v1 of a new charting API.

Having recently reviewed a series of charting frameworks for .NET, i settled on Aspose.Chart because it was simple, lightweight yet fully-featured.  I had a requirement for a bar graph overlaid with a line graph that used the y2 axis, and to be able to have labels for various data points along the way.  Something like this if you could imagine the red line was a bar:

So Google isn’t quite there yet for my requirements, but there are a heap of features, and such an elegant way to encode all the info into a compact query string.


The right balance for Dependency Injection (DI)

I agree with some remarks in Does Dependency Injection pay off in-so-far-as developers can overdue DI.

When going putting together a best practice framework for Domain-Driven Development using NHibernate i considered how best to configure the data access. NHibernate requires some additional session factory information in addition to the database connection string. In particular this references the assembly of Objects & Hbm embedded resources that map to the database + Other name/value configuration properties.

NHibernate supports a standard way of setting this configuration information. But I needed to support multiple databases (session-factories) and wanted this configuration to sit directly within the app.config, so i went about creating my own session factory configuration handler:

<nhibernate>
  <
sessionFactories>
  <
clearFactories />
  <
sessionFactory name="SessionFactoryName" connectionStringName="ConnectionStringName">
  <
settings>
  <
clear />
  <
add name="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"/>
  <
add name="hibernate.dialect"
value="NHibernate.Dialect.MsSql2005Dialect"/>
  <
add name="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"/>
  <
add name="hibernate.cache.provider_class"
value="NHibernate.Cache.HashtableCacheProvider,NHibernate"/>
  <
add name="hibernate.cache.use_query_cache"
value="true"/>
  </
settings>
  <
assemblies>
  <
clear />
  <
add assembly="Domain.Common" />
  </
assemblies>
  </
sessionFactory>
  </
sessionFactories>
</
nhibernate>

I structured the code in such a way that one IDaoFactory interface that was initialized with a SessionFactory name, and it passed this name down to its respectify IDao (repository) implementations that would then load the configuration information for loading the NHibernate ISession. So in essense I was not injecting the configuration information for the ojbect, but more a pointer so it could load the information. And by seperating the IDao contract, it makes it very easy to create a Dao stub that could be used for unit testing purposes.

It is also worth noting that in the top web layer i use Castle Windsor to inject the SessionFactory name’s into the IDaoFactory objects, so as to avoid hard coding any configuration information:

<castle>
  <
components>
  <
component id="primaryDaoFactory"
type="Data.NHibernateDaoFactory, Domain.Data"
service="Domain.Interfaces.IDaoFactory, Domain.Common">
<
parameters>
<
sessionFactoryName>DCDS</sessionFactoryName>
</
parameters>
</
component>
</
components>
</
castle>

This is only introduced at the web layer, so as to avoid the dependency on the Castle framework throughout the Domain model / data libraries. So to surmise I use DI techniques in constructing objects, but minimize the injection points so as to avoid develop confusion on how/when objects are initialized.


Practical example for ViewState

There have been considerable improvements in the way ViewState is serialized with ASP.NET 2, and with the added ControlState functionality it is possible for third party controls to behave themselves with ViewState disabled.

There are some great articles written on understanding ViewState like this one by Scott Mitchell. My practical example (see below) list some ways to minimizing view state.

My example utilises a custom TextBox control that raises events when it’s value has changed, or had saved its ViewState. In addition I persist the number of times it has ‘Changed’ to illustrate the key point:

  • A control with ViewState disabled will still fire its Change event if the posted-back value has changed when compared with its initialized value.

Developers often DataBind ListItem controls if (!PostBack) on Page_Load, however this results in the ViewState bloat. An alternative is to always DataBind on Page_Init, this is particularily useful for reference data that doesn’t change often and is ‘cheap’ to load:

  • A control DataBound in Page_Init routine it will still receive it’s PostBack event and post data without requiring ViewState.

Please see my View State Example project for more details.

Julian.