T4 Templates Part Duex

by jmorris 15. December 2010 23:04

I previously wrote about some experiences I have had with T4 templates and generating objects from database tables using the MSSQL metadata tables. Well another code generation opportunity came up and a comment by a reader pointed me in the direction of Damian Guard’s Manager.tt template so I decided to take a look. Nothing wrong with using something better than what you’ve already developed.

First up, a couple of observations with T4 and VS2010 (my previous experience with T4 in my post was using VS2008 and it would interesting to see how far T4 and IDE have come along).

“Save” Means “Execute”…Still!

The first thing I have noticed, which I was hoping would have changed, was the generation model/compilation model: when ever you hit Ctrl S, the template will save and immediately be run by the T4 engine. The problem with this is that if your doing a bunch of refactoring and if your work flow is modify/save/build (such as mine is, I blame TDD) then you’ll quickly slow down as the code generated that doesn’t compile will muck up VS. For example if you are generating a lot of files, things slow down to a stop if this happens after every save. I think it would be so much nicer if it was tied into it’s own command (such as in the Build dropdown) and instead of piggy-backing on “Save”.

Always Set debug=true!

This is super important -- always set debug to “true” on your template headers:

image

Doing this is the difference between pulling your hair out trying to figure what is failing and quickly fixing the issue and moving along

Assembly Locking is Major PITA: Use VolatileAssembly Directive from the T4 Toolbox!

Note: Apparently this is resolved in VS2010 SP1 (Thanks Will!)

One thing that you’ll quickly discover if your calling into code that exists outside of the template (such as the assembly that you are creating your templates in) is that the T4 engine will reuse the assemblies used by the templates, thus they will remain blocked while the engine is running. What this means is that you will have to close VS and reopen it if you want to modify the code in those assemblies (such as when you discover an issue in the code the template is using to generate your output).

Closing and Reopening Visual Studio is a major PITA and seriously cuts into your productivity. Fortunately, there is a workaround: download and install the T4 Toolbox from CodePlex.com and use the VolatileAssembly directive on one and only one template.

image

What this does is create a temporary copy of the referenced assembly for each template generation which is cleaned up after the generation completes.

Damien Guards Manager.tt Template Rocks!

Now for the grand finale: Damien Guards Manager.tt is awesome and really makes multi-file code generation easy. For details, check out his blog posting from the references below, but here is quick overview:

image

Here is a breakdown of what is going on:

  1. Include Damien’s Manager.tt T4 template
  2. Create a reference to the T4 generation environment
  3. Start a new file using StartNewFile(string fileName). The file’s body is created between this method call and the next EndBlock()
  4. EndBlock() stops the generation of the file’s body
  5. StartHeader() starts a new header section
  6. EndBlock() ends the header section
  7. Call Process() to generate the files

It’s really pretty straightforward and easy to use.

References

Tags: , , ,

T4

Parsing FTP LIST Command Results

by jmorris 3. December 2010 15:05

Background

As part of an automated process I have a service that recursively iterates through an FTP directory and pulls down any new or changed files saving them to disk before being uploaded into a CDN (Content  delivery network) where they are used on the Web. Another automated process digitalizes published magazines and writes the images and text as XML documents into this FTP directory (so it can be consumed). 

This has been running for some time when I noticed that there were a lot of images that were not being copied down from the FTP server. After some investigation I noticed that the only images with spaces in the name were failing to download and upon looking into my code it was pretty clear what was going wrong.

Processing the LIST Command Result

I was using the WebRequestMethods.Ftp.ListDirectoryDetails flag which makes the FtpWebRequest object use the FTP LIST command to retrieve the file names in each directory. The FTP server is a Unix based computer thus when I execute the directory LIST command it returns back a CLRF delimited blob of text containing a record describing each file in the directory as a record that looks like the following:


-rw-r--r--    1 1089    1091       505482 Nov 19 22:53 paper texture 2jpg1290206009609589.JPG

This breaks down into the following structure which is delimited by a space:

mode links owner  group  size datetime name
  -rw-r--r-- 1 1089 1091 505482 Nov 19 22:53 paper texture 2jpg1290206009609589.JPG

Note that there is another FTP command NLIST, which returns back just the filename itself which works just fine, but it doesn’t given you enough information about what kind of entry the file is. For example, if I encounter a folder, I want to step into and read the contents. If it’s a file, I want to download the file. The mode portion of the LIST result gives you the information required to make this is decision: if the first element is a “d”, it’s a directory so keep traversing…otherwise assume it’s a file so download it.

The Problem with Spaces (and my code)

When I process a LIST record string, I split it into an array and based on ordinal (position-the last element) I select the name element:

clip_image001

The problem is that when the name element has spaces, the last element is the last whole part of the file name – any proceeding parts are split into separate elements and ignored. So for most files, there were no problems; it wasn’t until files with spaces in the name began appearing did the appear.

Regular Expressions To The Rescue

A quick Google search revealed that people who have encountered this problem, used regex’s to correctly parse the LIST result record. In particular, this post on stackoverflow hit the nail on the head:

^(?<dir>[\-ld])(?<permission>([\-r][\-w][\-xs]){3})\s+(?<filecode>\d+)\s+(?<owner>\w+)\s+(?<group>\w+)\s+(?<size>\d+)\s+(?<timestamp>((?<month>\w{3})\s+(?<day>\d{2})\s+(?<hour>\d{1,2}):(?<minute>\d{2}))|((?<month>\w{3})\s+(?<day>\d{2})\s+(?<year>\d{4})))\s+(?<name>.+)$

A quick unit test confirms the simplest case:

image

Tags: , , , , , ,

C#

Jeff Morris

Tag cloud

Month List

Page List