What uigen.exe does
uigen.exe
generates a complete Visual Studio ASP.NET project from a re-motion domain, i.e. one or more assemblies containing the domain object classes constituting the domain. uigen.exe
gets a path to a directory, inspects all assemblies in it and checks whether it contains domain object classes. Based on what it sees, uigen.exe
generates a basic ASP.NET application to work with those domain objects.
uigen.exe
is template-based. It uses a directory tree with templates for generating a typical Visual Studio ASP.NET projects. The directory tree corresponds roughly to the generated tree.
This is how the "template tree" looks like:
This is how the generated tree for a PhoneBook ASP.NET application project looks like:
(The extra folders are bin
, obj
and Properties
. They are not part of uigen.exe
's program generation,
they are build products from building the PhoneBook web application from generated sources.)
The original tree contains files and templates from which uigen.exe
makes the actual files in the generated project – at the same relative path where their copies or expansions will show up in the generated tree. Some files - like images - are just copied.
A typical example is the top-level folder in the template tree. To the left you see the templates in uigen.exe
's root of the template tree, to the right you see the corresponding top-level of the generated PhoneBook tree:
In other words: most of the templates have the same name as the resulting file. The notable exception here is the name of the resulting project, in this case PhoneBook.Web.csproj
. This file originates from the template named WebClient.csproj
and is renamed in the course of template expansion.
If you open a template file, you will see that it contains "placeholders", denoted by "Dollar-Dollar". (e.g. "$WEB_CLIENT_GUID$
"):
'$(...)' snippets
The $(...)
items are NOT uigen-placeholders! They are Visual Studio placeholders!
You might recognize the highlighted placeholder $PROJECT_ROOTNAMESPACE$
in the picture: this is the placeholder you set in the uigen.exe
configuration file. It is substituted by the placeholders value (a string).
Other good examples for directories with template files corresponding to exactly one output file is the Classes
directory, with templates for
BaseControl.cs
BaseFunction.cs
BasePage.cs
EditFormPage.cs
Not all templates work in such a fun-and-easy 1:1 fashion, however. If you look into the WebClient\UI
template subfolder you will find the following templates:
NavigationTabs.ascx
NavigationTabs.ascx.cs
NavigationTabs.ascx.designer.cs
EditControl.ascx
EditControl.ascx.cs
EditControl.ascx.designer.cs
EditForm.aspx
EditForm.aspx.cs
EditForm.aspx.designer.cs
SearchResultForm.aspx
SearchResultForm.aspx.cs
SearchResultForm.aspx.designer.cs
All the first three files, NavigationTabs.
serve as templates not for a single file, but for one file per domain object class. For example, for each of the classes Location
, Person
and PhoneNumber
, a set of EditLocationControl.
, EditPersonControl.
. and EditPhoneNumberControl.
will be generated from the corresponding EditControl.*
templates.
The rule applies to EditForm.
and SearchResultForm.
. From the NavigationTabs.*
only one instance is generated, independently from the number of domain classes. These placeholders get their values from inspection of domain assemblies.
More about placeholders
Not all $PLACEHOLDERS$
get their values from the uigen.exe
configuration file as strings. Some placeholders get their values from other sources. The central example here are the names for domain object classes. uigen.exe
provides a mechanism to iterate over all domain object classes.
If you open the WebClient\UI\NavigationTabs.ascx
template, you will see three $PLACEHOLDER$
types:
$REPEAT_FOREACHCLASS_BEGIN$
$REPEAT_FOREACHCLASS_END$
$DOMAIN_CLASSNAME$
The $REPEAT_FOREACHCLASS_BEGIN$
and $REPEAT_FOREACHCLASS_END$
acts as a bracket around a loop, iterating over all domain object classes. The $DOMAIN_CLASSNAME$
acts as a counter variable with the current domain object class name as value. We call such special placeholders "Loopers".
This construction is needed in several templates – whenever some code/text has to be expanded for each domain object class.
WebClient\UI\NavigationTabs.ascx
is an example for iterating over domain object classes in a single template. This is in contrast to templates like WebClient\UI\EditForm.aspx
, which iterate over domain object classes and generate one file per domain object class. How can that be done? We will return to this question in section TabbedEditor.xml below. Let's look at how the looper constructions are used within a single file.
In more general terms, a looper is always based on a list of thingies (classes, properties, enums) that can be represented as strings. The class looper might be based on the list of classes Location
, Person
and PhoneNumber
(the classes in the PhoneBook). The class looper expands the text between the start placeholder and the end placeholder for each item in the list and uses the string representation as value for the iterator variable(s).
An example for the class looper at work is the UrlMapping.xml
template that expands to a full-blown UrlMapping.xml
configuration file for the PhoneBook app (for example). The task here is to create an EditX-
and SearchX-
entry for each domain object class in the domain (i.e. Location
, Person
and PhoneNumber
in the PhoneBook application).
Look at this section in the UrlMapping.xml
template:
$REPEAT_FOREACHCLASS_BEGIN$ <add id="Edit$DOMAIN_CLASSNAME$" type="... blah..." blah /> <add id="Search$DOMAIN_CLASSNAME$" type="... blah..." blah /> $REPEAT_FOREACHCLASS_END$
In the expanded UrlMapping.xml
file this section has been expanded three times, once for Location
, Person
and PhoneNumber
:
<add id="EditLocation" type="... <add id="SearchLocation" type="... <add id="EditPerson" type="... <add id="SearchPerson" type="... <add id="EditPhoneNumber" type="... <add id="SearchPhoneNumber" type="...
A looper can have more than one iterator variable. The class looper sports not only $DOMAIN_CLASSNAME$
, but also $DOMAIN_QUALIFIEDCLASSTYPENAME$
expanding to the class name plus namespace for the current class.
More loopers exist besides $REPEAT_FOREACHCLASS_BEGIN/END$. There are:
- $REPEAT_FOREACHPROPERTY_BEGIN/END$ -- iterates over properties in the class (not used in the PhoneBook web application) - $REPEAT_FOREACHENUM_BEGIN/END$ -- iterates over all enum types; deprecated, was used for injecting multilingual resources into the domain (see below) - REPEAT_FOREACHREFERENCEDPROPERTY_BEGIN/END$ -- iterates over reference properties or {{ObjectList}}|s
A complete list of placeholders can be found in the file Placeholder.cs
. Not all of them are used in the current templates.
Placeholders.cs
can be found here.
TabbedEditor.xml
(The many faces of application generation)
The uigen.exe
configuration file provides "placeholders" (macros) for substitution in other files, but not more. The central piece, the file that tells uigen.exe
what to do, is the TabbedEditor.xml
file. If you inspect it you will sense that generating a project for a re-motion ASP.NET web client application has several different parts:
- copying files from various directories to the web client project (directories)
- substituting place-holders in template files
- using a set of template files and class- and property names from the domain to create various .aspx .ascx and .cs files
- mapping property types to controls
- adding extra information to particular controls, like fixed column nodes for BocLists
In a way, the TabbedEditor.xml
file can be seen as a batch file written in a special programming language, and uigen.exe
can be seen as an interpreter for that language. The TabbedEditor.xml file is the batch file for creating tabbed editor applications (with their distinctive feature being that each domain object class gets its own tab/page in the application). You could write generators for other types of applications simply by writing a "batch file" like TabbedEditor.xml
with different instructions. Flexibility is limited, however, since the "batch language" is not Turing-complete.
When staring at uigen.exe
, alert readers will notice that TabbedEditor.xml
is itself a template file. The $PLACEHOLDERS$
, $WebClientName$
, $DomainProjectName$
, $DOMAIN_CLASSNAME$
, etc. put it away: TabbedEditor.xml
is subject to placeholder substitution and thus clearly a template. Its expansion is never stored anywhere, however.
Not contained in the template, however, are the looping elements $REPEAT_FOREACHCLASS_BEGIN$
and $REPEAT_FOREACHCLASS_END$
. This function is taken over by corresponding XML tags, namely <forEachClass>
and </forEachClass>
.
Another such looping element is <forEachEnum>
, with an iterator placeholder named $DOMAIN_ENUMNAME$
.
So TabbedEditor.xml
is the master configuration file for uigen.exe
. Apart from containing a list of files to copy and templates to expand it controls the following chores:
- generating globalization (resource) files for enums (currently commented out)
- mapping domain class property types to BOC controls
- injecting extra .aspx-XML into .aspx/.ascx-declarations
Each of the chores is discussed separately in the following sections.
Files and templates
uigen.exe
dedicates
- the
<file template=...>
operator to expanding single template files - the
<files pattern=...>
operator to expanding multiple template files, specified by path names with wild-cards - the
<copy source=...>
operator to simply copying multiple files with wildcards
This works for "inner expansion" and "outer expansion". Inner expansion means that the specified file(s) are expanded, and the expanded product gets the same name as the original template file. Example: In
<files pattern="WebClient*.aspx" target="$WebClientName$" />
the file default.aspx
is fingered (among others) in the template tree and expanded to the project tree as default.aspx
.
Outer expansion means that the specified file(s) are expanded for each class, and the expanded products each get a name that reflects the class for which it has been expanded. Example: In
<file template="WebClient\UI\EditControl.ascx" target="$WebClientName$\UI\Edit$DOMAIN_CLASSNAME$Control.ascx" />
the file EditControl.ascx
in the template tree is expanded to EditLocationControl.ascx
, EditPersonControl.ascx
and EditPhoneNumberControl.ascx
if there are three classes named Location
, Person
and PhoneNumber
.
All template expansion- and copy-operators under the node global are submitted to inner expansion, all the template expansions under the ndoe <forEachClass>
are subject to outer expansion.
Generating globalization (resource) files for enums
This looked like a good idea in 2006, but has run out of fashion since then. The argument is that it is bad taste for a program generator to add code to the DOMAIN, and globalizing enums clearly is part of the domain. That's why the corresponding section in TabbedEditor.xml
has been commented out.
Mapping domain class property types to BOC controls
This important mapping is expressed under the node properties/controlMappings and simply contains a set of operators – <mapping>
. Example: The line
<mapping propertyType="Remotion.ObjectBinding.IBusinessObjectEnumerationProperty" control="remotion:BocEnumValue" />
simply maps an enumeration property to a BocEnumValue
.
The extra optional attribute isList
controls whether the value can be represented by a list (drop-downlist, list box, etc.)
injecting extra .aspx-XML into .aspx/.ascx-declarations
Under the node properties/additionalAttributes
and properties/additionalElements
we find extra code for supplementing aspx-declarations for each property = extra attributes and extra elements.
Structure of the generated web project
Directories
bin
– contains the assembly for the actual web program, re-motion assemblies and the domain assembly/ies.Classes
– contains the base classes for re-call functions/pages. You are supposed to lodge the extra class files for your project here.Globalization
– the resources for globalizing your application.Images
– the images your application needs. Out of the box it contains an arrow-picture and a rubicon logores
– a local copy of re-motion-generic resources for the web client applicationUI
– the ASP.NET pages that comprise your application.
Other notable files
Default.aspx
,Default.aspx.cs
,Default.aspx.designer.cs
– generated from the templates of the same names. This is the "splash screen"/"start screen" you see after the application has started.Global.asax
,Global.asax.cs
the meat isGlobal.asax.cs
. Out of the box it initializes various provides. Put initialization code for your application here.UrlMapping.xml
– just what the name suggests, maps URLs to re-call page/functions. This file is created using the domain object classes as input (one entry per domain object class).Web.Config
– created from a template of the same name. This is your regular ASP.NET configuration file, of course.WxeFunctions.cs
– out of the box this file is empty. It is written by another code generator,wxegen.exe
.- WxeHandler.ashx – declares the handler for .wxe (re-call) "files".
Where to find uigen.exe
in the SVN-repository
For the re-motion version 1.13.6, the one supported by the PhoneBook tutorial:
https://svn.re-motion.org/svn/Remotion/trunk/Remotion/ObjectBinding/Web.CodeGenerator/
Later versions have a new uigen.exe
in
https://svn.re-motion.org/svn/Remotion-Contrib/Remotion.ObjectBinding.Web.CodeGenerator