|< Day Day Up >|| |
Perhaps you’ve never considered code generation as a viable way to build your own applications. In this section of the chapter, I’ll show you a simple (and common) example of a situation where a code-generation tool can save you a lot of time and effort. Then I’ll pass on a taxonomy of code-generation tools, and talk about some of the areas where code generation can be useful.
Let’s suppose you have a SQL Server database containing a number of tables. For this example, the standard Northwind database will do just fine. Being a good developer and wary of SQL injection problems, you’ve decided to use stored procedures for all of your code’s interaction with the database. It’s relatively easy to sit down and write the first of these stored procedures— say, a procedure that adds a record to the Categories table:
CREATE PROCEDURE [dbo].procAddCategories @CategoryName nvarchar(15), @Description ntext, @Picture image, @CategoryID int OUTPUT AS INSERT INTO [dbo].[Categories] ( [CategoryName], [Description], [Picture] ) VALUES ( @CategoryName, @Description, @Picture ) SET @CategoryID = @@IDENTITY
Easy enough—but of course the job doesn’t end with one stored procedure. You’ll probably want stored procedures to update existing records, delete records, return a single record, and return a list of records. And you’ll want these stored procedures for every table in the database. With a dozen tables in the database, you’re talking about 60 stored procedures here. Of course, they’re all easy to write; it will just take you an afternoon of boring cut-and-paste work, at least if you don’t make a mistake along the way.
Before spending time doing repetitive work in development, think about whether you can automate the task instead.
This situation is ideal for code generation. Instead of writing 60 stored procedures by hand, here’s how you could do it using CodeSmith (www.ericjsmith.net/codesmith/):
Launch CodeSmith and double-click the AllStoredProcedures.cst template to open its property sheet, shown in Figure 8.1.
Figure 8.1: CodeSmith template properties
Fill in the database connection and set other properties according to your preferences.
Click the Generate button. Figure 8.2 shows a portion of the output.
Figure 8.2: CodeSmith output
Copy the CodeSmith output to SQL Server Query Analyzer and execute it.
Now you can take the rest of the afternoon off, since the tool has done all the work that you’d planned to finish today.
CodeSmith works by using templates that are similar to ASP.NET pages. When you click the Generate button, the CodeSmith engine uses these templates, plus your inputs, to construct the desired output. The output can be any text at all, from a programming language to documentation to XML files. It’s limited only by your cleverness in designing the template.
Code-generation tools come in a variety of forms, from simple to complex, and are capable of tackling a variety of tasks. To understand where you might use code generation, it helps to have a breakdown of these tools into organized categories. Fortunately, someone has already done the hard work of creating such a classification. Jack Herrington’s book Code Generation in Action (Manning, 2003) and his Code Generation Network website (www.codegeneration.net) provide much information and many links for the developer interested in learning more about this field.
Herrington identifies two basic kinds of code generators: active and passive. A passive code generator dumps code into your project and forgets about it. The Data Form Wizard in Visual Studio .NET (VS .NET) is a perfect example of a passive code generator: It asks you some questions, and then builds the form for you. If you want to change the form, you need to run through the whole process again; you can’t go back and tell the wizard to just make a few changes.
You may or may not be familiar with SQL injection, but as a developer, it’s a problem that you should be aware of. While this is not a security book, I think it’s worth a small amount of space to make sure that you understand the basics.
SQL injection is most typically a problem in web applications that build up a query based on user input. For example, an ASP.NET application might contain this line of code:
SqlString = "SELECT * FROM Customers WHERE CompanyName = \"" + txtName.Text + "\""
Later on, a SqlCommand object could be used to execute the specified SQL statement and return results. The problem arises because of the user input. A sufficiently malicious user could enter this text into the txtName control:
A";DELETE FROM Orders --
Because SQL Server sees the semicolon as a statement separator, this is interpreted as two statements. The first selects customers where the CompanyName column contains the value A. The second deletes every row from the Orders table! The trailing -- causes SQL Server to treat anything following as a comment.
You can choose among several strategies to prevent SQL injection in your own application. One approach is to attempt to validate user input to ensure that it doesn’t contain dangerous characters. Another is to use stored procedures, which in general are not vulnerable to this problem.
For additional information on SQL injection, I strongly recommend you read these two white papers:
SQL Injection: Are Your Web Applications Vulnerable? (www.spidynamics.com/papers/SQLInjectionWhitePaper.pdf)
Advanced SQL Injection in SQL Server Applications (www.nextgenss.com/papers/advanced_sql_injection.pdf)
By contrast, an active code generator takes responsibility for maintaining the code. When you want to change the classes produced by an active code generator, you tweak the input file or the code generator itself; you never directly edit the output. Herrington identifies six basic types of active code generation:
The code munger takes an input file, parses it, and creates an output file from some built-in or external template.
The inline-code expander takes source code with some special markup and creates production code from it. Embedded-SQL generators, which allow you to drop SQL statements into C or Java code (for example), work this way.
The mixed-code generator is similar to the inline-code expander, except that the results are written right back to the input file. For example, special comments might specify delegate code that needs to be created and added to the file.
The partial-class generator reads some sort of abstract definition file and builds a base class source code file to implement the definition. The user can then create a derived class to get the final desired functionality.
The tier generator builds an entire tier (typically, a data-access tier) from an abstract definition. UML products that integrate with your IDE can fall into this class.
The full-domain language is a Turing-complete programming language created just for your problem. It gives you a general-purpose way to specify code that should be created.
Within this taxonomy are many, many code-generation tools for the .NET languages. Some, like the CodeSmith tool that I briefly demonstrated earlier in the chapter, are very general-purpose tools. Others are targeted at one specific area, such as creating business objects or building database-backed web applications.
Don’t get the impression that code generation is only concerned with putting out source code that you can then feed into a compiler. It’s better to think of code generation as a technology for automatically generating a variety of end products, only some of which fall into the traditional category of “code.” Here are just a few examples of things that you might produce using code generation:
Database-access code This includes stored procedures and data-access classes.
User-interface code This might be your final production code, or it might be quickly mocked-up code that allows you to test classes in your project.
Documentation Think about the XML comments in C#, which can be turned into HTML help by NDoc. You’ll learn more about NDoc in Chapter 12, “Creating Documentation.”
Unit tests If you’re going to generate code, why not generate tests for the code as well?
Web services You could write a Web Services Description Language (WSDL) file and have all the code needed to implement it automatically generated.
DLL wrappers for legacy code Indeed, the .NET Framework will do some of this for you when you set a reference to a COM library from your .NET project.
Configuration files or initialization files For example, you might automatically generate an app.config file for your application based on a customer name and license key number.
Scripting files You could use Windows Management Instrumentation (WMI) and VBScript to provision websites into a new installation of Internet Information Services (IIS), for example.
Installation files The Windows Installer service works by looking at tables in a database, and there’s no reason that you couldn’t build some or all of those tables with a code-generation tool.
What it boils down to is this: If you can describe an output that you’d like to get, you can likely build a code generator to take the description to the actual output. (This leaves aside the question as to whether it’s more work to write the output or build the generator.)
|< Day Day Up >|| |