Generating Code

The DSL Tools provide a rich templating technology that enables you to generate output based on your domain model; and as discussed previously, this technology is used to create your designer and can be used by your own designer. It can also be used by your designer to generate your output of choice — source code and documentation are common examples.

In the scenario of your Navigation Designer, you want to generate ASP.NET Pages and their associated code-behind files for each of the pages in the language model. As placeholders, you could create buttons on each page that will navigate to any child pages linked using the connector.

At the time of writing, the DSL Tools do not provide a way for a template to output multiple files during execution. In our scenario, we need to generate an .ASPX and ASPX.CS file for every Page defined in our navigation model, so we are unable to generate pages using the templates. This feature is planned in the final product. If you were to use the templating technology, you would define a template of a shell ASPX and ASPX.cs file and provide .NET code to iterate around the object model creating pages.

For the purposes of the book, we will implement the page generation manually using .NET code. The principles are in fact identical to how templates will work, but you have to provide a bit more plumbing.

You start by defining the template for the ASPX and ASPX.cs files by creating a new Web Site project and use the default pages generated as a base for your templates. Any page-specific information has to be replaced with tokens that you can then replace with the page specifics during generation.

The ASPX and ASPX.cs templates are shown in the following code examples. You can see that tokens have been added at key places (highlighted in bold). Where the data is the same, we use the same token identifier, and any curly braces in the code need to be escaped with an extra curly brace. Here is TemplatePage.aspx:

      <%@ Page Language="C#" AutoEventWireup="true" CodeFile="{0}.aspx.cs"      Inherits="{0}" %>      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"      "">      <html xmlns="" >      <head runat="server">          <title>Untitled Page</title>      </head>      <body>          <form  runat="server">          <h1>{1}</h1>          <div>              {2}          </div>          </form>      </body>      </html> 

Here is the corresponding ASPX.CS template. The number of using statements to import namespaces has been reduced for clarity:

      TemplatePage.aspx.cs      using System;      public partial class {0} : System.Web.UI.Page      {{          {1}      }} 

Now that you have your templates, you need to write the code that will iterate through all of the pages in the domain model and generate the physical implementations. As you create pages, you also need to create buttons on the pages to demonstrate the navigation defined in the domain model, so you have some boilerplate button definitions, which you use to simplify insertion of these buttons into the page code.

The code shown retrieves a collection of all the Pages in your domain model and iterates through each one in turn. You then load the templates into a string so you can replace the tokens with the page-specific information.

For each page, you then obtain any child Pages referenced by the Page and construct a button for each one, enabling the user to navigate to them. You also generate the code-behind file that performs the transfer between pages using Response.Redirect.

You then replace any tokens in the two files with the page-specific information and then output the text for the pages to disk. Following its execution, you will see .ASPX and .ASPX.cs files generated:

      const string ButtonDefinition = "<asp:Button ID=\"{0}\" runat=\"server\"      Text=\"{0}\" OnClick=\"{0}_Click\" />";      const string ButtonCodeDefinition = "protected void {0}_Click(object sender,      EventArgs e)\r\n{{\r\n{1}\r\n}}";      IList MELPages =      this.Store.ElementDirectory.GetElements(DomainModel.Page.MetaClassGuid);      foreach (DomainModel.Page MELPage in MELPages)      {          //Read the ASP.NET Page Templates into a string so we can customise.          StreamReader ASPXTemplatePageReader = new StreamReader("TemplatePage.aspx");          string TemplateASPXPage = ASPXTemplatePageReader.ReadToEnd();          StreamReader CodeTemplatePageReader = new StreamReader("TemplatePage.aspx.cs");          string TemplateCodePage = CodeTemplatePageReader.ReadToEnd();          //We loop around any Child Pages and provide buttons on the ASP.NET Page and          //Code Behind handlers to move to the child pages          StringBuilder ASPXButtonDefinitions = new StringBuilder();          StringBuilder CodeButtonDefinitions = new StringBuilder();          foreach (DomainModel.Page MELChildPage in MELPage.ChildPages)          {              //Variable and type names cannot have spaces so we remove              string CollapsedChildName = MELChildPage.Name.Replace(" ", "");              //Create a new ASP.NET Button              ASPXButtonDefinitions.Append( String.Format(ButtonDefinition,                                          CollapsedChildName) );             //Create the Code behind for the button             string NavigationCode = String.Format(                           "Response.Redirect(\"{0}.aspx\");", CollapsedChildName );             CodeButtonDefinitions.Append(String.Format(ButtonCodeDefinition,                                          CollapsedChildName, NavigationCode ) );          }          //Variable and type names cannot have spaces so we remove          string CollapsedName = MELPage.Name.Replace(" ", "");          //Our page templates have the areas that need          //to change for each page replaced with tokens which we now fill in.          string OutputASPXPage = String.Format(TemplateASPXPage, CollapsedName,                          MELPage.Name, ASPXButtonDefinitions.ToString() );          string OutputCodePage = String.Format(TemplateCodePage, CollapsedName,                                                CodeButtonDefinitions.ToString() );          using (StreamWriter ASPXPageWriter = new StreamWriter( CollapsedName +                                                               ".aspx" ) )          {              ASPXPageWriter.Write(OutputASPXPage);          }          using (StreamWriter ASPXPageWriter = new StreamWriter( CollapsedName +                                                                ".aspx.cs"      ) )          {              ASPXPageWriter.Write(OutputCodePage);          }      } 

If you then copy these files into a new ASP.NET website and navigate to Logon.aspx, you should see the logon page as defined in the language model appear as shown in Figure 6-17.

image from book
Figure 6-17

Clicking one of the buttons will enable you to navigate to the page as defined in the language model. For example, clicking ViewStatement will take you to the View Statement page (shown in Figure 6-18), which only has a link to the Signoff page.

image from book
Figure 6-18

As you can see, generating these pages was extremely straightforward, and even a complex navigation model would require much less development effort. The templating support in the DSL Tools makes generation of these pages even easier.

If you wanted to produce an Avalon version of your site or move to another page technology, you could simply replace the templates and regenerate the pages. Using the domain model in this way effectively decouples you from the implementation technology.

Professional Visual Studio 2005 Team System
Professional Visual Studio 2005 Team System (Programmer to Programmer)
ISBN: 0764584367
EAN: 2147483647
Year: N/A
Pages: 220 © 2008-2017.
If you may any questions please contact us: