Thursday 13 October 2011

ASP NET MVC 3 T4 Template Properties

Here are the properties that ASP.NET MVC 3.0 provides to T4 templates when you use the Add View and Add Controller dialogs inside Visual Studio 2010.

Add Controller

Property Name Type Description
AddActionMethods Boolean Adds action methods to the generated controller class.
AreaName System.String The name of the Area that the controller is created for.
ContextType System.Type The type of the data context.
ControllerName String The name of the controller class that will be generated.
ControllerRootName String The name of the controller class excluding the Controller part at the end of the name.
EntitySetName String Name of the property on the data context class containing the set of entities.
ModelType System.Type The type of the model class specified in the Add Controller dialog.
Namespace String Namespace that will be used for the generated controller class.
PrimaryKeys PrimaryKey[]
(Microsoft.
VisualStudio.
Web.Mvc.
Scaffolding.
BuiltIn)
Primary keys for the model. See table at end for PrimaryKey properties.
RelatedProperties Dictionary<String,
RelatedModel
(Microsoft.
VisualStudio.
Web.
Mvc.
Scaffolding.
BuiltIn)>
Related properties on the model. See table at end for RelatedModel properties.

Add View

Property Name Type Description
AreaName System.String The name of the Area that the view is being created for.
ContentPlaceHolderIDs List<string> List of content place holder IDs in the master page.
IsContentPage Boolean True if the generated view will be created with a master page or a Razor layout page.
IsPartialView Boolean True if the generated view is a partial view (e.g. an ASP.NET user control).
MasterPageFile String Master page file or Razor layout to be used with view (e.g. ~/Views/Shared/Site.Master).
Namespace String Namespace that will be used for the generated view.
PrimaryContentPlaceHolderID String Primary content place holder ID to be used when creating a view using a master page.
ReferenceScriptLibraries Boolean True if checked in the Add View dialog.
ViewDataType System.Type The view model's type.
ViewDataTypeName String Fully qualified name for the view model's type.
ViewName String Name of the view.

Common Properties

Property Name Type Description
AssemblyPath List<string> List of assemblies referenced by the project and the project's output assembly. Internal use.
Errors CompilerErrorCollection
(System.CodeDom.Compiler)
Used to stored errors that occur whilst processing the T4 template. Internal use.
FileEncoding System.Text.Encoding The encoding of the file that will be generated.
FileExtension String Not set.
FrameworkVersion System.Version The .NET framework version.
OutputFileExtension System.String The extension of the file that will be generated.
TemplateFile System.String The full path to the T4 template file being used.

Primary Key Properties

Property Name Type Description
Name String
ShortTypeName String
Type System.Type

Related Model Properties

Property Name Type Description
DisplayPropertyName String
EntitySetName String
ForeignKeyPropertyName String
PrimaryKey String
PropertyName String
TypeName String

Tuesday 4 October 2011

T4 Import Directive - Namespace Alias

How do you specify a namespace alias when using the Import directive in a T4 template?

The Import directive in a T4 template is used to bring a namespace into scope for any code that will be run when processing the T4 template. Here is an example template that imports the System.IO namespace without using a namespace alias.

<#@ template language="C#" #> 
<#@ output extension=".txt" #> 
<#@ import namespace="System.IO" #> 
<# 
 string text = File.ReadAllText(@"d:\MyFile.txt"); 
#> 
File content: <#= text #>

The T4 template reads all the text in the d:\MyFile.txt which is then saved in the file generated by the template.

If we want to use a namespace alias we can specify it in the import directive in a similar way to how you can with C# or VB.NET. Here is the example template modified so that an alias of IO is used for the System.IO namespace.

<#@ template language="C#" #> 
<#@ output extension=".txt" #> 
<#@ import namespace="IO = System.IO" #> 
<# 
 string text = IO.File.ReadAllText(@"d:\temp\test.xsd"); 
#> 
File content: <#= text #>

Why does this Work?

T4 templates use the CodeDom to generate C# or VB.NET code which is then executed as the template is processed. When the T4 templating engine processes the Import directive it creates a CodeNamespaceImport object and passes it the Namespace attribute's value. The CodeNamespaceImport object supports generating a namespace alias when you specify a string of the form "Alias = Namespace" and pass this to its constructor.

Sunday 21 August 2011

Creating a JavaScript Parser with ANTLR that can be used from CSharp

How do you create a JavaScript parser that you can use from C#? One way is to use ANTLR. ANother Tool for Language Recognition (ANTLR) is a parser generated created and maintained by Terence Parr.

The ANTLR website has a JavaScript grammar already defined so we will take that grammar, get ANTLR to create a parser, and then use that parser to parse some JavaScript code. The following guide is based on using ANTLRWorks 1.4.2, which includes ANTLR 3.3, and the CSharp3 code generator version 3.3.1.

Installing ANTLR

  1. Install the Java JDK 1.5. Newer versions than 1.5 may work with ANTLR.
  2. Download ANTLRWorks 1.4.2 (which includes Antlr 3.3).

Check ANTLRWorks can be started by either double clicking the antlrworks-1.4.2.jar file or opening a command prompt and running the following command.

java -jar antlrworks-1.4.2.jar

Generating a JavaScript Parser

Download a JavaScript grammar from http://www.antlr.org/grammar/list.

I used Chris Lambrou's JavaScript grammar since this was the most recent.

Open the JavaScript.g file in ANTLRWorks by selecting Open from the File menu.

Edit the JavaScript.g file and add "language=CSharp3" to the options section.

options 
{ 
    output=AST; 
    backtrack=true; 
    memoize=true; 
    language=CSharp3; 
}

The language determines what language the parser code will be generated in. To generate C# there are 3 choices for the language.

  1. CSharp (.NET 1.1 code generated)
  2. CSharp2 (.NET 2.0 code generated)
  3. CSharp3 (.NET 3 code generated)

To specify a namespace for the generated C# classes add another line to the JavaScript.g file.

    @namespace { ICSharpCode.JavaScriptBinding }

In ANTLRWorks select Generate Code from the Generate menu. Three files should be generated in an output directory below where JavaScript.g file is located

  • JavaScript.tokens
  • JavaScriptLexer.cs
  • JavaScriptParser.cs

The two C# files are the ones we are interested in and we will now take a look at how we can use them in a C# application.

Using the JavaScript Parser

The C# files that were generated depend on another set of assemblies.

If you generated code using the CSharp3 target then download the CSharp3 assemblies.

For code generated using the CSharp2 and CSharp then download the CSharp2 assemblies.

In both cases the assembly you need is Antlr3.Runtime.dll so extract that file from the downloaded zip file.

Now we need to use our parser and lexer.

Create a C# console project and add the JavaScriptLexer.cs and JavaScriptParser.cs files into the project. Add a reference to the Antlr3.Runtime.dll.

Compile the project.

If you receive an error about HIDDEN being undefined then rename HIDDEN to Hidden in the JavaScriptLexer.cs file.

Remove the "[System.CLSCompliant(false)]" from the lexer and parser files to fix the warning about not requiring CLSCompliant to be set.

In order to get access to the results the parser generates you will need to make a modification to the JavaScriptParser.cs. Make the program() method public, as shown below.

    public JavaScriptParser.program_return program()

If you generate the parser and lexer as java source code files this method is public but for it is private when using any of the CSharp targets.

The correct way to fix the problem with the program method being private is to modify the JavaScript grammar file. If you add the public keyword to JavaScript.g grammar file as shown below then after regenerating the lexer and parser files using ANTLRWorks the program method will be public.

public program 
    : LT!* sourceElements LT!* EOF! 
    ; 

Now how do we use the parser? The following code shows you how.

using System; 
using Antlr.Runtime; 
using Antlr.Runtime.Tree; 
using ICSharpCode.JavaScriptBinding; 
 
namespace JavaScriptParserConsole 
{ 
    class Program 
    { 
        public static void Main(string[] args) 
        { 
            try { 
                string text = "var a = 1;"; 
                 
                var stream = new ANTLRStringStream(text); 
                var lexer = new JavaScriptLexer(stream); 
                var tokenStream = new CommonTokenStream(lexer); 
                var parser = new JavaScriptParser(tokenStream); 
                JavaScriptParser.program_return programReturn = parser.program(); 
                 
            } catch (Exception ex) { 
                Console.WriteLine(ex.ToString()); 
            } 
             
            Console.Write("Press any key to continue..."); 
            Console.ReadKey(true); 
        } 
    } 
} 

First we have some JavaScript code to parse. In this case we have a simple variable assignment. This JavaScript code is then passed to a ANTLRStringStream class. The lexer takes this stream and produces a set of tokens. We turn the lexer into a CommonTokenStream and then this is passed to the parser. The program_return class returned from the parser is an Abstract Syntax Tree (AST). Getting access to the AST will depend on how the grammar has been defined. In the JavaScript grammar the top part of the AST is called program.

public program 
    : LT!* sourceElements LT!* EOF! 
    ;

This maps to a method called program in our parser class.

Does a grammar always create an AST? It depends on the grammar options. For the JavaScript grammar we are using:

options 
{ 
    output=AST; 
    backtrack=true; 
    memoize=true; 
    language=CSharp3; 
}

The output is defined to be AST so ANTLR generates classes to produce an AST after parsing the source code. There are two options for output: AST and template. If this option is not specified the default is AST.

Now we still have not done anything useful with the parse results. So let us display the AST.

using System; 
using Antlr.Runtime; 
using Antlr.Runtime.Tree; 
using ICSharpCode.JavaScriptBinding; 
 
namespace JavaScriptParserConsole 
{ 
    class Program 
    { 
        public static void Main(string[] args) 
        { 
            try { 
                string text = "var a = 1;"; 
                 
                var stream = new ANTLRStringStream(text); 
                var lexer = new JavaScriptLexer(stream); 
                var tokenStream = new CommonTokenStream(lexer); 
                var parser = new JavaScriptParser(tokenStream); 
                JavaScriptParser.program_return programReturn = parser.program(); 
                 
                var tree = programReturn.Tree as CommonTree; 
                WriteTree(tree); 
                 
            } catch (Exception ex) { 
                Console.WriteLine(ex.ToString()); 
            } 
             
            Console.Write("Press any key to continue..."); 
            Console.ReadKey(true); 
        } 
         
        static void WriteTree(CommonTree tree) 
        { 
            WriteLine("Tree.Text: " + tree.Text); 
            WriteLine("Tree.Type: " + tree.Type); 
            WriteLine("Tree.Line: " + tree.Line); 
            WriteLine("Tree.CharPositionInLine: " + tree.CharPositionInLine); 
            WriteLine("Tree.ChildCount: " + tree.ChildCount); 
            WriteLine(""); 
             
            if (tree.Children != null) { 
                IncreaseIndent(); 
                foreach (CommonTree child in tree.Children) { 
                    WriteTree(child); 
                } 
                DecreaseIndent(); 
            } 
        } 
         
        static int indent = 0; 
         
        static void WriteLine(string text) 
        { 
            string indentText = String.Empty.PadRight(indent * 2); 
            Console.WriteLine(indentText + text); 
        } 
         
        static void IncreaseIndent() 
        { 
            indent++; 
        } 
         
        static void DecreaseIndent() 
        { 
            indent--; 
        } 
    } 
} 
 

We have taken the program_return class that is returned from the parser's program method and displayed its tree.

    public class program_return 
        : ParserRuleReturnScope<IToken>, IAstRuleReturnScope<object> 
    { 
        private object _tree; 
        public object Tree { 
            get { return _tree; } 
            set { _tree = value; } 
        } 
    }

The Tree property is a CommonTree but by default ANTLR returns this as an object. We then pass this tree to a method that displays a few properties from the tree and then looks at the tree's children and displays them. Each child is also a tree so we call the WriteTree method recursively. With the simple javascript code of "var a = 1;" we get the following output when running this code:

Tree.Text: 
Tree.Type: 0 
Tree.Line: 1 
Tree.CharPositionInLine: 0 
Tree.ChildCount: 4 
 
  Tree.Text: var 
  Tree.Type: 37 
  Tree.Line: 1 
  Tree.CharPositionInLine: 0 
  Tree.ChildCount: 0 
 
  Tree.Text: a 
  Tree.Type: 5 
  Tree.Line: 1 
  Tree.CharPositionInLine: 4 
  Tree.ChildCount: 0 
 
  Tree.Text: = 
  Tree.Type: 39 
  Tree.Line: 1 
  Tree.CharPositionInLine: 6 
  Tree.ChildCount: 0 
 
  Tree.Text: 1 
  Tree.Type: 7 
  Tree.Line: 1 
  Tree.CharPositionInLine: 8 
  Tree.ChildCount: 0 
 

Can we specify the type of the Tree? The answer is yes. In the JavaScript grammar we can specify the type to be used for the Tree property by using the ASTLabelType.

options 
{ 
    output=AST; 
    backtrack=true; 
    memoize=true; 
    ASTLabelType=CommonTree; 
    language=CSharp3; 
} 

So we can set the tree's type to be CommonTree and we would not need to convert the Tree property from an Object to a CommonTree each time. With this change made the lexer and parser class files need to be regenerated with AntlrWorks. We also have to make the fixes described above (HIDDEN and ClsCompliant) to the generated code.

Now the program_return class has been changed:

    public class program_return 
        : ParserRuleReturnScope<IToken>, IAstRuleReturnScope<CommonTree> 
    { 
        private CommonTree _tree; 
        public CommonTree Tree {
            get { return _tree; } 
            set { _tree = value; }
        } 
    } 

Unfortunately this code does not compile and we get the error shown below.

Error CS0738: 'ICSharpCode.JavaScriptBinding.JavaScriptParser.program_return' does not implement interface member 'Antlr.Runtime.IAstRuleReturnScope.Tree'. 'ICSharpCode.JavaScriptBinding.JavaScriptParser.program_return.Tree' cannot implement 'Antlr.Runtime.IAstRuleReturnScope.Tree' because it does not have the matching return type of 'object'.

Looking at the interface definitions it looks like there is a problem with the code generation since the new program_return class does not implement the IAstRuleReturnScope interface completely:

    public interface IAstRuleReturnScope<TAstLabel> 
        : IAstRuleReturnScope, IRuleReturnScope 
    { 
        TAstLabel Tree 
        { 
            get; 
        } 
    } 
     
    public interface IAstRuleReturnScope : IRuleReturnScope 
    { 
        object Tree 
        { 
            get; 
        } 
    }

So we will have to switch back to not defining the tree's type by not using the ASTLabelType option.

Summary

In summary we have taken an existing JavaScript grammar, generated a parser using ANTLR and then used this parser to parse some JavaScript code and display the results held in the AST.