Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

NAVIGATION - SEARCH

Advanced ASP.NET caching events

Currently, I'm giving an ASP.NET classroom training at our company, which actually is quite good for me: I needed to refresh all ASP.NET concepts, as those all fade away slowly when you don't use them for a while... Now, one of those refreshed concepts is ASP.NET's caching.

ASP.NET offers a flexible built-in caching mechanism, providing you with a global "Cache" object in which you can get and put data which needs to be cached for a while. One of the cool things about ASP.NET caching is that it actually listens to what you want: if you need the cache to expire after 10 minutes, it does so. Also, when memory is needed for other actions on the webserver, ASP.NET will gently clean the cache depeding on cache item priorities.

As for many things in this world, every good thing also has a downside... And here's the downside for ASP.NET's caching: when an item is removed from cache, you'll have to know and react to that. No problem, you say, as you can simply use an if-statement to fix things up. Here's a DataDet which will be cached to infinity (or untill memory is needed):

[code:c#]

if (Cache.Get("myDataSet") == null) {
    // Re-fetch data
    // ... DataSet ds = ....

    Cache.Insert(
        "myDataSet", ds, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration
    );
}

[/code]

Great thing! But... What if I want to centralise cache creation? What if I want to log something everytime a cache item has been removed due to memory limits being reached? Luckily, ASP.NET provides an answer to that: the System.Web.Caching.CacheItemRemovedCallback delegate. This delegate can be used to ask ASP.NET to notigy you using a delegate of what is happening inside the cache when something is removed from it. Here's the delegate signature:

[code:c#]

void (string key, Object value, CacheItemRemovedReason reason);

[/code]

As you can see, you can get the key that's being removed, its current value, and the reason why the item is being deleted. These reasons can be: Expired, Removed, Underused, and DependencyChanged. I think these speak for themselves, no?

Now let's implement this: I'll create a CacheRetrievalManager which will update my cache whenever an item is removed from cache:

[code:c#]

using System;
using System.Web.Caching;

public class CacheRetrievalManager
{
    public void RemovedCacheItemHandler(string key, Object value, CacheItemRemovedReason reason)
    {
        switch (key)
        {
            case "myDataSet":
                // call method to re-fetch data and re-set cache
                // ...
                break;
        }
    }
}

[/code]

One thing left is to specify that this method should be called whenever a cache item is removed:

[code:c#]

// Insert in cache ONCE, recreation will be handled by CacheRetrievalManager
DataSet ds = ...;
Cache.Insert(
    "myDataSet", ds, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheRetrievalManager.RemoveCacheItemHandler
);

[/code]

Now I know exactly why something is removed, and that I can even log when this happens. You can now further extend this into separate CacheRetrievalManagers for every object you which to cache, fetch data inside that manager, ...

OpenXML in Healthcare in PHP

Here's a cool present just before the weekend... 2 days ago, Wouter posted on his blog about an article he co-operated on for MSDN: OpenXML in Healthcare.

Being both a Microsoft and PHP fan (yes, you can curse me, I don't care), I thought of porting (part of) the sample code from his article into PHP. Except for the document signing, as I did not have many time to write this sample code...

The scenario for the article is quite simple: Contoso provides a central medical records database. Whenever a physician has to register a new patient, he downloads a Word 2007 document from the Contoso server, fills it out, and uploads it back. Contoso then strips out the necessary data and saves it back in their systems.

 

This Word 2007 document is crafted around embedded custom XML data, which is displayed and edited using Word 2007. In short: to do the above exercise, you just need to strip out the custom XML and you're done.

Stripping out the custom XML is also quite easy. First, locate the main relationships part in the OpenXML package. Then, search it for the main document part. From there, loop over the relationships to this document part and look for any relationship of the type "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml". When that one's found, you just need to parse the referenced document and you're done!

Want to see a demo? Check this out.
Want the sample code? 2007HealthCareSamplePHP.zip (49.76 kb)
 Want the OpenXML background? Read the original article.

Generic arrays in PHP

Assuming everyone knows what generics are, let's get down to business right away. PHP does not support generics or something similar, though it could be very useful in PHP development.  Luckily, using some standard OO-practises, a semi-generic array can easily be created, even in multiple ways! Here's the road to PHP generics. 

The hard way...

One of the roads to PHP generics is some simple inheritance and type hinting. Let's have a look at PHP's ArrayObject. This class has 2 interesting methods, namely offsetSet() and append(). This would mean I can simply create a new class which inherits from ArrayObject, and uses type hinting to restrict some additions:

[code:c#]

// Example class
class Example {
  public $SomeProperty;
}

// Example class generic ArrayObject
class ExampleArrayObject extends ArrayObject {
  public function append(Example $value) {
    parent::append($value);
  }

  public function offsetSet($index, Example $value) {
    parent::offsetSet($index, $value);
  }
}


// Example additions
$myArray = new ExampleArrayObject();
$myArray->append( new Example() ); // Works fine
$myArray->append( "Some data..." ); // Will throw an Exception!

[/code]

The flexible way

There are some disadvantages to the above solution. For a start, you can't create a generic "string" array unless you encapsulate strings in a specific object type. Same goes for other primitive types. Let's counter this problem! Here's the same code as above using a "GenericArrayObject":

[code:c#]

// Example class
class Example {
  public $SomeProperty;
}

// Validation function
function is_class_example($value) {
  return $value instanceof Example;
}

/**
 * Class GenericArrayObject
 *
 * Contains overrides for ArrayObject methods providing generics-like functionality.
 *
 * @author    Maarten Balliauw
 */
class GenericArrayObject extends ArrayObject {
    /**
     * Validation function
     *
     * @var     string
     * @access    private
     */
    private $_validationFunction = '';
       
    /**
     * Set validation function
     *
     * @param     string    $functionName    Validation function
     * @throws     Exception
     * @access    public
     */
    public function setValidationFunction($functionName = 'is_string') {
        if ($this->_validationFunction == '') {
            $this->_validationFunction = $functionName;
            return;
        }
       
        $iterator = $this->getIterator();
        while ($iterator->valid()) {
            if (!call_user_func_array($functionName, array($iterator->current()))) {
                throw new Exception("Switching from " . $this->_validationFunction . " to " . $functionName . " is not possible for all elements.");
            }
           
            $iterator->next();
        }
       
        $this->_validationFunction = $functionName;
    }
   
    /**
     * Append
     *
     * @param     mixed    $value
     * @throws     Exception
     * @access    public
     */
    public function append($value) {
        if ($this->_validationFunction == '') {
            throw new Exception("No validation function has been set.");
        }
       
        if (call_user_func_array($this->_validationFunction, array($value))) {
            parent::append($value);
        } else {
            throw new Exception("Appended type does not meet constraint " . $this->_validationFunction);
        }
    }
   
    /**
     * offsetSet
     *
     * @param     mixed    $index
     * @param     string    $newval
     * @throws     Exception
     * @access    public
     */
    public function offsetSet($index, $newval) {
        if ($this->_validationFunction == '') {
            throw new Exception("No validation function has been set.");
        }
       
        if (call_user_func_array($this->_validationFunction, array($newval))) {
            parent::offsetSet($index, $newval);
        } else {
            throw new Exception("Appended type does not meet constraint " . $this->_validationFunction);
        }
    }
}

// Example additions
$myArray = new GenericArrayObject();
$myArray->setValidationFunction('is_class_example');
$myArray->append( new Example() ); // Works fine
$myArray->append( "Some data..." ); // Will throw an Exception!

[/code]

Using this flexible class, you can simply set a validation function on the GenericArrayObject, which enabels you to use PHP's built-in functions like is_string (string-only ArrayObject), is_int, ... You can even write a small validation function which matches a string against a regular expression and for example create an e-mail address ArrayObject rejecting any string that does not match this regular expression.

Inheritance is evil!

Read this on Bernie's blog:

"All of the pain caused by inheritance can be traced back to the fact that inheritance forces 'is-a' rather than 'has-a' relationships. If class R2Unit extends Droid, then a R2Unit is-a Droid. If class Jedi contains an instance variable of type Lightsabre, then a Jedi has-a Lightsabre.

The difference between is-a and has-a relationships is well known and a fundamental part of OOAD, but what is less well known is that almost every is-a relationship would be better off re-articulated as a has-a relationship."

I suggest you read the full story, as it's very interesting! Bottom line is that you should be careful using OO inheritance, and use the Strategy pattern instead.

Enabling HTTP proxy for .NET webservice client

Have you ever written code that makes external (Soap) webservice calls? Tried that same code on your company network? Most of the time, this does not work very well due to a proxy server sitting in between, requiring authentication etc.

You can start tweaking your Web.config file to set this proxy the right way, or you can override the generated web service class and include the following code snippet:

[code:c#]

using System;
using System.Net;

public class SomethingProxyEnabledService : com.example.service.something {
    protected override System.Net.WebRequest GetWebRequest(Uri uri) {
        WebRequest request = base.GetWebRequest(uri);

        request.Proxy = WebRequest.DefaultWebProxy;
        request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;

        return request;
    }
}

[/code]

The only thing left to do is use this "SomethingProxyEnabledService" class instead of the regular "com.example.service.something". There you go, automagical proxy authentication!

Remove unnecessary HTTP modules from the ASP.NET pipeline

Trying to speed up some things in a demo ASP.NET application for a customer, I found a really simple and effective way to remove some HTTP modules from the ASP.NET pipeline. When you are not using WindowsAuthentication or PassportAuthentication or ..., you can easily disable those modules. This decreases ASP.NET bootstrapping time as there are fewer object creations to do every page load...

Now, how to do this? Very easy! Fire up your Visual Studio, and open Web.config.
In the HttpModules section, add some "remove" elements, one for every module you whish to disable. If HttpModules section is not present, you can add it yourself.

[code:xml]

...
<httpModules>
    <remove name="WindowsAuthentication"/>
    <remove name="PassportAuthentication"/>
    <remove name="UrlAuthorization"/>
    <remove name="FileAuthorization"/>
</httpModules>
...

[/code]

Here are the default HttpModules that are present and can eventually be disabled:

  • OutputCache
  • Session
  • WindowsAuthentication
  • FormsAuthentication
  • PassportAuthentication
  • RoleManager
  • UrlAuthorization
  • FileAuthorization
  • AnonymousIdentification
  • Profile
  • ErrorHandlerModule (I'm sure you want this one enabled!)
  • ServiceModel

Check C:\WINDOWS\microsoft.NET\Framework\<version>\CONFIG\Web.config for more things you can emit. There are probably some more things you can override in your own Web.config...

Now assume you have a public and protected part on your website. The public part is www.example.com, the private part is www.examle.com/protected. Thanks to ASP.NET's configuration cascading model, you can now disable FormsAuthentication for www.example.com, as no authentication will be needed there. In the www.private.com/protected folder, you can now put another Web.config file, enabling FormsAuthentication on that folder. How cool is that!

I'm on my way to vacation. No blog posts next week, unless I spot a bear somewhere.

Creating Office2007 documents in C#

I've been too busy implementing SpreadsheetML in PHP, that I completely forgot to write something on OpenXML and C# on my blog. Luckily, Joris did now: Generating Office 2007 documents in C#. Now learn some PHP too, Joris, I can use a hand on PHPExcel [:P]

Here are some additional links to get you started:

Automatically generate SandCastle documentation using CruiseControl.NET or VSTS Team Build

Earlier this week, I was playing around with SandCastle, and found that the SandCastle Help File Builder (SHFB) was a great tool to quickly create SandCastle documentation. No more XML writing, just a few clicks and documentation is compiled into a HTML Help file or as a MSDN-style website.

Next to the GUI being quite handy, there's also a command-line tool in the download of SHFB... Now wouldn't it be nice if you could just create a configuration file using SHFB, and automatically compile documentation on your build server every weekend? Here's a short how-to, for both CruiseControl.NET (ccnet) and VSTS Team Build!

Shared steps

Get the right tools

First of all, download and install the right tools on your build machine:

This should not be difficult, right?

Fix a small bug...

In the 1.5.0.1 release of SHFB, there is a small bug... Navigate to the file C:\Program Files\EWSoftware\Sandcastle Help File Builder\Templates\MRefBuilder.config, open it with Notepad, and replace %DXROOT% with {@SandcastlePath} on line 4.

Setup your project file the right way

Next, make sure that your application build outputs XML code comment files. To do this, open your project file's property dialog, and enable "XML documentation file".

Create a SHFB configuration file

Now, create a SHFB configuration file for your solution. Make sure you include the necessary libraries and XML comment files. Also, try building the configuration file you just created. It often occurs you need to add a link to another assembly in your configuration too. If that assembly does not have any XML comments, you can use this one: Unknown.XML (right-click, Save As...).

Use the "Namespaces" button on the top-right of the SHFB screen to include/exclude specific namespaces (useful for external assemblies!), and to provide a short description of those namespaces for use in the help file.

In my case, I added this file (and Unknown.XML) to a SourceSafe repository, which will be used by ccnet to always fetch the latest documentation configuration file.

One thing to keep in mind: references to assemblies that should be documented, must be located from the build server's perspective! This means that when your build folder is C:\builds\, your assembly paths must resolve to that location somehow (relative or absolute). 

CruiseControl.NET

If you are using ccnet as your build server, the following steps are required to add a documentation build to your build server!

Locate your ccnet.config file, and add a new project:

[code:xml]

<cruisecontrol>
  <project name="SandCastle_Documentation">
    <workingDirectory>C:\SandCastle_Documentation\</workingDirectory>
    <artifactDirectory>C:\SandCastle_Documentation\Generated\</artifactDirectory>
    <modificationDelaySeconds>0</modificationDelaySeconds>
    <sourcecontrol>
      <!-- ... Fetch Documentation.shfb here! ... -->
    </sourcecontrol>
    <triggers>
      <scheduleTrigger time="21:00" buildCondition="ForceBuild">
        <weekDays>
          <weekDay>Sunday</weekDay>
        </weekDays>
      </scheduleTrigger>
    </triggers>
    <tasks>
      <exec>
        <executable>C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe</executable>
        <baseDirectory>C:\SandCastle_Documentation\</baseDirectory>
        <buildArgs>"C:\SandCastle_Documentation\Documentation.shfb"</buildArgs>
        <buildTimeoutSeconds>10800</buildTimeoutSeconds> <!-- 3 hours -->
      </exec>
      <exec>
        <executable>xcopy</executable>
        <buildArgs>"C:\SandCastle_Documentation\Generated" "C:\Inetpub\wwwroot\SandCastle_Documentation" /E /Q /H /R /Y</buildArgs>
        <buildTimeoutSeconds>3600</buildTimeoutSeconds> <!-- 1 hour -->
      </exec>
    </tasks>
    <publishers>
      <xmllogger logDir="c:\Program Files\CruiseControl.NET\Log" />
    </publishers>
  </project>
</cruisecontrol>

[/code]

There are two notheworthy steps here, located inside the <tasks> element. The first task you see there is used to call the SHFB command line tool and instruct it to generate documentation. Now since I want to create a MSDN-style documentation website, I added a second step, copying the deliverables to a folder in my wwwroot. For both steps, make sure you extend the default <buildTimeoutSeconds>! Over here, the thing takes a hour and a half to complete both steps, you see I have configured a larger amount of time there...

Finished? Restart the CruiseControl.NET system service, and you are ready to build SandCastle documentation automatically! 

VSTS Team Build

If you are using VSTS Team Build as your build server, the following steps are required to add a documentation build to your build server!

Locate your TFSbuild.proj file, check it out, and add a build target at the end of the file:

[code:xml]

<Target Name="AfterCompile">
    <Exec Command="&quot;C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe&quot; &quot;C:\SandCastle_Documentation\Documentation.shfb&quot;" />
    <Exec Command="xcopy &quot;C:\SandCastle_Documentation\Generated&quot; &quot;C:\Inetpub\wwwroot\SandCastle_Documentation&quot;  /E /Q /H /R /Y" />
</Target>

[/code]

There is one notheworthy step here: the first target task you see is used to call the SHFB command line tool and instruct it to generate documentation. Now since I want to create a MSDN-style documentation website, I added a second task, copying the deliverables to a folder in my wwwroot.

Check-in the build file, and build the solution! SandCastle documentation will now be integrated in your build process.

PackageExplorer, not only great for OpenXML...

The last few days, I've been working with Wouter to discuss some new features and ideas for his PackageExplorer. PE is an editor for OpenXML packages, enabling you to view the contents and relations of different parts in a package, to validate XML against OpenXML schemes, ...

One of the cool things we discussed was a HTML start page. Since Visual Studio has one, we decided PE should have one too. After creating a simple mock for this, Wouter was first to Google for a way to embed images and HTML in a resource file, and display it in a fancy start page (second price, for slow Google searchers: I designed the page [<:o)]). You can see the code and build steps required over at Wouter's.

Next cool thing: a new splash screen model. Always wanted to do things right with threads? No more white gaps in your screen due to a blocked UI thread? I suggest you read the eventing and threading explanation at (again) Wouter's blog.

Next suggestion: download PE, even if you don't know a thing about OpenXML. Want to learn how to use OO patterns? Always wanted to provide add-in functionality for your own application? PE's code gives a lot of answers on those questions!

Microsoft Tafiti just released

I'm sure you have already heared of SilverLight before, right? If not: it's Microsoft's answer to Adobe Flash, providing the same features + XAML-like markup + easier databinding + ... Now you're up to date: the Redmond people have just released a new site, Microsoft Tafiti, which is basically Live Search combined with a rich SilverLight interface. Tafiti means "do research" in Swahili. Don't think I'm a native Swahili speaker though, I found this here 8-)

The screenshot I made was first rendered in FireFox. No need to worry your SilverLight application not going to work on other systems than Windows + IE!

If this is the way the web is evolving, I like it! Slick graphics, but not the "feeling" you are working in a browser plugin.