Software Development

Spring.Net Cache & Complex Keys

So you want to cache the results of a service dll using the Spring.NET CacheResult attribute… But your class takes a List or complex object as part of the method call. No worries, you can use a helper class to generate your cache keys for you!

So my problem, I wanted to cache the result of this method call:

No problem, I’ll just slap a CacheResult attribute on the method and have Spring do the work for me!

All looks good! AspNetCache is defined in my Spring.Config to use the built in ASPNetCache and the CacheKey is generated using SpEL (Spring Expression Language). It can do nice things like get property values on your object if you pass in a complex type, or test conditions. Read up if you are not familiar with the syntax.

Well after some testing all is not well. All calls to the method are resulting in the same data being returned. So i do a little bit of debugging and find this!

Well I guess SpEL doesnt magicly handle collections when creating a cache key. After some digging I discover that SpEL can invoke CLR objects! This means we can use a helper class to generate the cache key. This has the added bonus of letting us toss some tests around the key generation since this could have quite easilly slipped out into production if we were not careful.

CacheKeyHelper to the rescue.

So lets change tha Key string so it uses this new calss.

Well that doesnt work. SpEL doesnt cleanly handle generics yet. Then I remember that SpEL can invoke objects that are registered in the spring config using @(ID_NAME).Method syntax.

XML to the rescue!

So I declare an instance of the CacheKeyHelper class for string types, and I modify my CacheResult attribute to use this new instance.

Success!

Software Development

Comments (1)

Permalink

Mediawiki SEO: 301 redirects

I was asked to change Mediawiki’s #REDIRECT handling from transparent redirects to SEO friendly 301 redirects. I tried to create some extensions but none of the hooks seemed to provide a way to change the redirect functionality the way I needed to.

Turns out I only needed to edit Article.php and Wiki.php with very minor 1 line changes. Haven’t seen this posted anywhere else so enjoy.

#Article.php - Changed line 32 to return $rt->getFullUrl();
function followRedirect() {
  $text = $this->getContent();
  $rt = Title::newFromRedirect( $text );
 
  # process if title object is valid and not special:userlogout
  if( $rt ) {
    if( $rt->getInterwiki() != '' ) {
      if( $rt->isLocal() ) {
              // Offsite wikis need an HTTP redirect.
              //
              // This can be hard to reverse and may produce loops,
              // so they may be disabled in the site configuration.
 
              $source = $this->mTitle->getFullURL( 'redirect=no' );
              return $rt->getFullURL( 'rdfrom=' . urlencode( $source ) );
          }
      } else {
          if( $rt->getNamespace() == NS_SPECIAL ) {
              // Gotta handle redirects to special pages differently:
              // Fill the HTTP response "Location" header and ignore
              // the rest of the page we're on.
              //
              // This can be hard to reverse, so they may be disabled.
 
              if( $rt->isSpecial( 'Userlogout' ) ) {
                  // rolleyes
              } else {
                  return $rt->getFullURL();
              }
          }
          return $rt->getFullUrl();
      }
  }
 
  // No or invalid redirect
  return false;
}
#Wiki.php - Changed line 11 to $output->redirect( $article, "301" );
function initialize ( &$title, &$output, &$user, $request) {
    wfProfileIn( 'MediaWiki::initialize' );
    $this->preliminaryChecks ( $title, $output, $request ) ;
    $article = NULL;
    if ( !$this->initializeSpecialCases( $title, $output, $request ) ) {
        $article = $this->initializeArticle( $title, $request );
        if( is_object( $article ) ) {
            $this->performAction( $output, $article, $title, $user, $request );
        } elseif( is_string( $article ) ) {
            $output->redirect( $article, "301" );
        } else {
            throw new MWException( "Shouldn't happen: MediaWiki::initializeArticle() returned neither an object nor a URL" );
        }
    }
    wfProfileOut( 'MediaWiki::initialize' );
    return $article;
}

Software Development

Comments (4)

Permalink