sparkviewengine 1.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/docs/index.html ADDED
@@ -0,0 +1,2835 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
3
+ <head>
4
+ <title>Spark Documentation</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <base href="http://sparkviewengine.com" />
7
+ <link type="text/css" rel="stylesheet" href="misc/print.css" />
8
+ </head>
9
+ <body>
10
+
11
+ <div id="node-4" class="section-1">
12
+ <h1 class="book-heading">Spark Documentation</h1>
13
+ <h3 id="WhatisSpark">What is Spark</h3>
14
+
15
+ <p>Spark is a view engine for Asp.Net Mvc and Castle Project MonoRail frameworks. The idea is to allow the html to dominate the flow and the code to fit seamlessly.</p>
16
+
17
+ <p>For example,</p>
18
+
19
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
20
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">'var p in ViewData.Model.Products'</span><span class="re2">&gt;</span></span>
21
+ ${p.Name} !{Html.ActionLink[[ProductController]](c=&gt;c.Edit(p.Id), &quot;Edit&quot;)}
22
+ <span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
23
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
24
+
25
+ <p>The full csharp language is available in a way that doesn't interfere with the harmony and balance of the markup. The view template files produced compiled classes.</p>
26
+
27
+ <h3 id="Needsdocumentation">Needs documentation</h3>
28
+
29
+ <ul>
30
+ <li>Web-Application relative <code>~/</code> urls</li>
31
+ <li>Support for <code>&lt;def&gt;</code> and <code>&lt;var&gt;</code></li>
32
+ <li>Capture content directly to variables</li>
33
+ <li>Inner text on partial views</li>
34
+ <li>monorail view components</li>
35
+ <li>clientside rendering</li>
36
+ <li>javascript clientside views</li>
37
+ <li>Use of ${expr} and !{expr} and automaticEncoding</li>
38
+ <li>late bound ${#prop} and ${Eval("prop")}</li>
39
+ <li>view areas</li>
40
+ </ul>
41
+ <div id="node-10" class="section-2">
42
+ <h1 class="book-heading">Configuring Spark</h1>
43
+ <div class="toc">
44
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
45
+ <div class="toc-list">
46
+ <ul>
47
+
48
+ <ul>
49
+
50
+ <ul>
51
+ <li><a href="#AddingtoCastleMonoRail">Adding to Castle MonoRail</a></li>
52
+ <li><a href="#AddingtoAspNetMVC">Adding to Asp.Net MVC</a></li>
53
+ <li><a href="#Sparksettingsinconfigfile">Spark settings in config file</a></li>
54
+ <li><a href="#Sparksettingsincode">Spark settings in code</a></li>
55
+ </ul>
56
+ </li>
57
+ </ul>
58
+ </li>
59
+ </ul>
60
+ </div>
61
+ </div>
62
+
63
+ <h3 id="AddingtoCastleMonoRail">Adding to Castle MonoRail</h3>
64
+
65
+ <p>In the web application add references to the <strong>Castle.MonoRail.Views.Spark</strong> and <strong>Spark</strong> assemblies.</p>
66
+
67
+ <p>In the &lt;monorail&gt; section configure the spark view engine.</p>
68
+
69
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;monorail<span class="re2">&gt;</span></span></span>
70
+ <span class="sc3"><span class="re1">&lt;viewEngines</span> <span class="re0">viewPathRoot</span>=<span class="st0">&quot;Views&quot;</span><span class="re2">&gt;</span></span>
71
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">type</span>=<span class="st0">&quot;Castle.MonoRail.Views.Spark.SparkViewFactory, Castle.MonoRail.Views.Spark&quot;</span><span class="re2">/&gt;</span></span>
72
+ <span class="sc3"><span class="re1">&lt;/viewEngines<span class="re2">&gt;</span></span></span>
73
+ <span class="sc3"><span class="re1">&lt;/monorail<span class="re2">&gt;</span></span></span></pre></div></p>
74
+
75
+ <p>That's about it really.</p>
76
+
77
+ <h3 id="AddingtoAspNetMVC">Adding to Asp.Net MVC</h3>
78
+
79
+ <p><em>View engines are no managed by the controller. This section is now correct for Preview 5</em></p>
80
+
81
+ <p>The simplest way to use Spark from an Asp.Net MVC web application is to register an instance of the SparkViewFactory inn your Global Application_Start function at the same point you would be registering routes and such.</p>
82
+
83
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">protected</span> <span class="kw1">void</span> Application_Start<span class="br0">&#40;</span><span class="kw4">object</span> sender, EventArgs e<span class="br0">&#41;</span>
84
+ <span class="br0">&#123;</span>
85
+ ViewEngines.<span class="me1">Engines</span>.<span class="me1">Add</span><span class="br0">&#40;</span><span class="kw3">new</span> SparkViewFactory<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
86
+ <span class="br0">&#125;</span></pre></div></p>
87
+
88
+ <p>This is also an excellent place to provide any other non-default services to the view factory. Such as an IViewFolder that reads from embedded resources instead of the file system, or an IViewActivatorFactory which can take over the responsibility of instantiating the compiled view types.</p>
89
+
90
+ <p><em>todo - document use of IoC for this</em></p>
91
+
92
+ <h3 id="Sparksettingsinconfigfile">Spark settings in config file</h3>
93
+
94
+ <p>After the Spark view engine is integrated into your MVC, MonoRail, or other application there are some additional settings you may want to configure. One way to do this is with a &lt;spark&gt; config file section.</p>
95
+
96
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;configSections<span class="re2">&gt;</span></span></span>
97
+ <span class="sc3"><span class="re1">&lt;section</span> <span class="re0">name</span>=<span class="st0">&quot;spark&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;Spark.Configuration.SparkSectionHandler, Spark&quot;</span><span class="re2">/&gt;</span></span>
98
+ <span class="sc3"><span class="re1">&lt;/configSections<span class="re2">&gt;</span></span></span>
99
+ <span class="sc3"><span class="re1">&lt;spark<span class="re2">&gt;</span></span></span>
100
+ <span class="sc3"><span class="re1">&lt;compilation</span> <span class="re0">debug</span>=<span class="st0">&quot;true|false&quot;</span> <span class="re0">defaultLanguage</span>=<span class="st0">&quot;Default|CSharp|VisualBasic&quot;</span><span class="re2">&gt;</span></span>
101
+ <span class="sc3"><span class="re1">&lt;assemblies<span class="re2">&gt;</span></span></span>
102
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">assembly</span>=<span class="st0">&quot;YourAssemblyName&quot;</span> <span class="re2">/&gt;</span></span>
103
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">assembly</span>=<span class="st0">&quot;YourOtherStrongAssemblyName, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35&quot;</span> <span class="re2">/&gt;</span></span>
104
+ <span class="sc3"><span class="re1">&lt;/assemblies<span class="re2">&gt;</span></span></span>
105
+ <span class="sc3"><span class="re1">&lt;/compilation<span class="re2">&gt;</span></span></span>
106
+ <span class="sc3"><span class="re1">&lt;pages</span> <span class="re0">automaticEncoding</span>=<span class="st0">&quot;true|false&quot;</span> <span class="re0">pageBaseType</span>=<span class="st0">&quot;Your.NonDefault.BaseSparkView&quot;</span> <span class="re0">prefix</span>=<span class="st0">&quot;{optional string}&quot;</span><span class="re2">&gt;</span></span>
107
+ <span class="sc3"><span class="re1">&lt;namespaces<span class="re2">&gt;</span></span></span>
108
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">namespace</span>=<span class="st0">&quot;System&quot;</span><span class="re2">/&gt;</span></span>
109
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">namespace</span>=<span class="st0">&quot;System.Collections.Generic&quot;</span><span class="re2">/&gt;</span></span>
110
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">namespace</span>=<span class="st0">&quot;System.Linq&quot;</span><span class="re2">/&gt;</span></span>
111
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">namespace</span>=<span class="st0">&quot;System.Web.Mvc&quot;</span><span class="re2">/&gt;</span></span>
112
+ <span class="sc3"><span class="re1">&lt;/namespaces<span class="re2">&gt;</span></span></span>
113
+ <span class="sc3"><span class="re1">&lt;resources<span class="re2">&gt;</span></span></span>
114
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">match</span>=<span class="st0">&quot;/content/css&quot;</span> <span class="re0">location</span>=<span class="st0">&quot;http://www.yourcdnprovider.com/youraccount/allstyles/css&quot;</span><span class="re2">/&gt;</span></span>
115
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">match</span>=<span class="st0">&quot;/content/js&quot;</span> <span class="re0">location</span>=<span class="st0">&quot;http://www.yourcdnprovider.com/youraccount/appname/js&quot;</span><span class="re2">/&gt;</span></span>
116
+ <span class="sc3"><span class="re1">&lt;/resources<span class="re2">&gt;</span></span></span>
117
+ <span class="sc3"><span class="re1">&lt;/pages<span class="re2">&gt;</span></span></span>
118
+ <span class="sc3"><span class="re1">&lt;/spark<span class="re2">&gt;</span></span></span></pre></div></p>
119
+
120
+ <p>The defaultLanguage may be specified if you are using a language like VisualBasic. It's not necessary for nearly any other case.</p>
121
+
122
+ <p>Additional assemblies and namespaces can be referenced with &lt;use assembly="..." namespace="..." /&gt; in view, layout, and partial files. All assemblies loaded in the app domain are automatically referenced, there may be times you want to add references explicitly for assemblies that aren't yet loaded.</p>
123
+
124
+ <p>The default page base type, MvcContrib.SparkViewEngine.SparkView or Castle.MonoRail.Views.Spark.SparkView, will be used if one isn't specified. If you do provide a class as the page base type you'll probably inherit from the default base class.</p>
125
+
126
+ <p>Automatic HTML encoding of output may be enabled. This will result in every instance of ${expr} output passing through the intrinsic HTML encoding method H(). The syntax !{expr} is used in this case for output which should be sent unencoded.</p>
127
+
128
+ <p>An optional prefix may be selected, which must then be used on all Spark elements and attributes in your template files. The prefix should not be set here if you're defining a prefix in the templates with xmlns attributes.</p>
129
+
130
+ <p>The resources section may be used to control the result of ~/ style urls. For example, <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;script</span> <span class="re0">src</span>=<span class="st0">&quot;~/content/js/foo.js&quot;</span><span class="re2">/&gt;</span></span></code></span> will normally appear as a ${SiteRoot} prefixed url but the match for "/content/js" above will make that url appear as the given location + "/foo.js". The assumption for high-volume sites is you would use the normal urls for development and map them to a static file server or to a cdn provider in production.</p>
131
+
132
+ <h3 id="Sparksettingsincode">Spark settings in code</h3>
133
+
134
+ <p>Another way to provide these settings to the spark engine is to provide an ISparkSettings instance to the constructor.</p>
135
+
136
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">protected</span> <span class="kw1">void</span> Application_Start<span class="br0">&#40;</span><span class="kw4">object</span> sender, EventArgs e<span class="br0">&#41;</span>
137
+ <span class="br0">&#123;</span>
138
+ <span class="kw4">var</span> settings <span class="sy0">=</span> <span class="kw3">new</span> SparkSettings<span class="br0">&#40;</span><span class="br0">&#41;</span>
139
+ .<span class="me1">SetDebug</span><span class="br0">&#40;</span><span class="kw1">true</span><span class="br0">&#41;</span>
140
+ .<span class="me1">SetPageBaseType</span><span class="br0">&#40;</span><span class="st0">&quot;Your.NonDefault.BaseSparkView&quot;</span><span class="br0">&#41;</span>
141
+ .<span class="me1">AddAssembly</span><span class="br0">&#40;</span><span class="st0">&quot;YourAssembly&quot;</span><span class="br0">&#41;</span>
142
+ .<span class="me1">AddNamespace</span><span class="br0">&#40;</span><span class="st0">&quot;System&quot;</span><span class="br0">&#41;</span>
143
+ .<span class="me1">AddNamespace</span><span class="br0">&#40;</span><span class="st0">&quot;System.Collections.Generic&quot;</span><span class="br0">&#41;</span>
144
+ .<span class="me1">AddNamespace</span><span class="br0">&#40;</span><span class="st0">&quot;System.Linq&quot;</span><span class="br0">&#41;</span>
145
+ .<span class="me1">AddNamespace</span><span class="br0">&#40;</span><span class="st0">&quot;System.Web.Mvc&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
146
+ &nbsp;
147
+ ViewEngines.<span class="me1">Engines</span>.<span class="me1">Add</span><span class="br0">&#40;</span><span class="kw3">new</span> SparkViewFactory<span class="br0">&#40;</span>settings<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
148
+ <span class="br0">&#125;</span></pre></div></p>
149
+ </div>
150
+ <div id="node-9" class="section-2">
151
+ <h1 class="book-heading">General Syntax</h1>
152
+ <p><div class="toc">
153
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
154
+ <div class="toc-list">
155
+ <ul>
156
+
157
+ <ul>
158
+
159
+ <ul>
160
+ <li><a href="#Basicmarkup">Basic markup</a></li>
161
+ <li><a href="#Includingcode">Including code</a></li>
162
+ <li><a href="#Specialcharactersincode">Special characters in code</a></li>
163
+ <li><a href="#Sparkelementprefixwithconfig">Spark element prefix with config</a></li>
164
+ <li><a href="#Sparkelementprefixwithxmlnsnamespaces">Spark element prefix with xmlns namespaces</a></li>
165
+ </ul>
166
+ </li>
167
+ </ul>
168
+ </li>
169
+ </ul>
170
+ </div>
171
+ </div></p>
172
+
173
+ <h3 id="Basicmarkup">Basic markup</h3>
174
+
175
+ <p>A view file has basic html markup that can appear pretty much as you'd expect.</p>
176
+
177
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
178
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello <span class="sc3"><span class="re1">&lt;span<span class="re2">&gt;</span></span></span>world<span class="sc3"><span class="re1">&lt;/span<span class="re2">&gt;</span></span></span>!<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
179
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
180
+
181
+ <h3 id="Includingcode">Including code</h3>
182
+
183
+ <p>CSharp code may be used to produce output. Any helper methods, object properties, or expression that evaluates to a non-void value can be used.</p>
184
+
185
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${&quot;Hello world&quot;}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
186
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${Guid.NewGuid().ToString(&quot;n&quot;)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span></pre></div></p>
187
+
188
+ <p>Code will also appear in special attributes or elements like "if", "else", and "var". These types of areas will never require ${} or <%= %> notation.</p>
189
+
190
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">names</span>=<span class="st0">&quot;new [] {'alpha', 'beta', 'gamma'}&quot;</span><span class="re2">/&gt;</span></span>
191
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var name in names&quot;</span><span class="re2">&gt;</span></span>
192
+ <span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">&quot;name == 'beta'&quot;</span><span class="re2">&gt;</span></span>
193
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>beta is my favorite.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
194
+ <span class="sc3"><span class="re1">&lt;else</span><span class="re2">/&gt;</span></span>
195
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${name} is okay too I suppose.
196
+ <span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span>
197
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></pre></div></p>
198
+
199
+ <p>However if you use code to produce a normal attribute's value, that is not a special attribute does require the code-output notation.</p>
200
+
201
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">currentProduct</span>=<span class="st0">&quot;Product&quot;</span><span class="re2">/&gt;</span></span>
202
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${currentProduct.Name} <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;/Product/Edit/${currentProduct.Id}&quot;</span><span class="re2">&gt;</span></span>Edit<span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span></pre></div></p>
203
+
204
+ <h3 id="Specialcharactersincode">Special characters in code</h3>
205
+
206
+ <p>The entire functionality of the csharp language is available. As always, please use responsibly. :) Be sure to put business logic in your controller's actions and write unit test for it.</p>
207
+
208
+ <p>There are a small number of characters that are parsed in a special way to avoid simple mechanical problems you can encounter in a standard xml editor.</p>
209
+
210
+ <p>The sequences [[ and ]] are parsed as if they are < and >. This can be convenient when you're using generic classes or methods from a spark file, to avoid the editor's tendency to add a closing elements for you. The [[ and ]] will not be changed if they occur inside a string literal.</p>
211
+
212
+ <p>String literals may be expressed in 'single quotes' in addition to "double quotes". This is again for convenience when using expressions inside attributes values that are contained in double quotes. If you do need to use a single char constant in an expression, using an explicit type-cast (char)'x' will avoid having the string changed to "x".</p>
213
+
214
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">products</span>=<span class="st0">&quot;IList[[Products]]&quot;</span><span class="re2">/&gt;</span></span>
215
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">styles</span>=<span class="st0">&quot;new[] {'even', 'odd'}&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
216
+
217
+ <h3 id="Sparkelementprefixwithconfig">Spark element prefix with config</h3>
218
+
219
+ <p>By default, Spark tags are unqualified. All of the examples you'll see are written that way. That can cause a problem if Spark is being used to create xml rather than xhtml. One of the ways to disambiguate spark xml from output xml is to set a prefix for your application.</p>
220
+
221
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;spark<span class="re2">&gt;</span></span></span>
222
+ <span class="sc3"><span class="re1">&lt;pages</span> <span class="re0">prefix</span>=<span class="st0">&quot;s&quot;</span><span class="re2">/&gt;</span></span>
223
+ <span class="sc3"><span class="re1">&lt;/spark<span class="re2">&gt;</span></span></span></pre></div></p>
224
+
225
+ <p>Or<br />
226
+ <div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">var</span> settings <span class="sy0">=</span> <span class="kw3">new</span> SparkSettings<span class="br0">&#40;</span><span class="br0">&#41;</span>
227
+ .<span class="me1">SetPrefix</span><span class="br0">&#40;</span><span class="st0">&quot;s&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
228
+
229
+ <p>At which point all of the native spark elements and attributes must include the s: prefix to be recognized. None of the built-in prefixes macro:, content:, use:, render:, and section: are affected by the use of the prefix setting.</p>
230
+
231
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
232
+ <span class="sc3"><span class="re1">&lt;s:viewdata</span> <span class="re0">user</span>=<span class="st0">&quot;UserInfo&quot;</span><span class="re2">/&gt;</span></span>
233
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">s:if</span>=<span class="st0">&quot;user != null&quot;</span><span class="re2">&gt;</span></span>${user.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
234
+ <span class="sc3"><span class="re1">&lt;s:LoginForm</span><span class="re2">/&gt;</span></span>
235
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
236
+
237
+ <h3 id="Sparkelementprefixwithxmlnsnamespaces">Spark element prefix with xmlns namespaces</h3>
238
+
239
+ <p>Another way to disambiguate the markup is to declare xmlns attributes, which will result in well-formed and valid xml. All of the Spark namespace Uris begin with <a href="http://sparkviewengine.com/" title="http://sparkviewengine.com/">http://sparkviewengine.com/</a>. If a template file contains a Spark xmlns attribute then the other built-in prefixes (macro:, etc.) will only function if their namespace Uri's are also declared. </p>
240
+
241
+ <table>
242
+ <tr>
243
+ <th>Default prefix</th>
244
+ <th>Namespace Uri</th>
245
+ </tr>
246
+ <tr>
247
+ <th>none - spark tags and partial files</th>
248
+ <th>http://sparkviewengine/</th>
249
+ </tr>
250
+ <tr>
251
+ <th>content:</th>
252
+ <th>http://sparkviewengine/content/</th>
253
+ </tr>
254
+ <tr>
255
+ <th>use:</th>
256
+ <th>http://sparkviewengine/use/</th>
257
+ </tr>
258
+ <tr>
259
+ <th>macro:</th>
260
+ <th>http://sparkviewengine/macro/</th>
261
+ </tr>
262
+ <tr>
263
+ <th>section:</th>
264
+ <th>http://sparkviewengine/section/</th>
265
+ </tr>
266
+ <tr>
267
+ <th>render:</th>
268
+ <th>http://sparkviewengine/render/</th>
269
+ </tr>
270
+ </table>
271
+
272
+ <p>You can use the defaults or specify any prefix you choose. Once an xmlns attribute is defined only the value on the namespace Uri is significant.</p>
273
+
274
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html</span> <span class="re0">xmlns</span>=<span class="st0">&quot;http://www.w3.org/1999/xhtml&quot;</span>
275
+ <span class="re0">xmlns:s</span>=<span class="st0">&quot;http://sparkviewengine.com/&quot;</span>
276
+ <span class="re0">xmlns:fn</span>=<span class="st0">&quot;http://sparkviewengine.com/macro/&quot;</span><span class="re2">&gt;</span></span>
277
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
278
+ <span class="sc3"><span class="re1">&lt;fn:ShowNames</span> <span class="re0">favorite</span>=<span class="st0">&quot;string&quot;</span><span class="re2">&gt;</span></span>
279
+ <span class="sc3"><span class="re1">&lt;s:var</span> <span class="re0">names</span>=<span class="st0">&quot;new [] {'alpha', 'beta', 'gamma'}&quot;</span><span class="re2">/&gt;</span></span>
280
+ <span class="sc3"><span class="re1">&lt;s:for</span> <span class="re0">each</span>=<span class="st0">&quot;var name in names&quot;</span><span class="re2">&gt;</span></span>
281
+ <span class="sc3"><span class="re1">&lt;s:test</span> <span class="re0">if</span>=<span class="st0">&quot;name == favorite&quot;</span><span class="re2">&gt;</span></span>
282
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${favorite} is my favorite.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
283
+ <span class="sc3"><span class="re1">&lt;s:else</span><span class="re2">/&gt;</span></span>
284
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${name} is okay too I suppose.
285
+ <span class="sc3"><span class="re1">&lt;/s:test<span class="re2">&gt;</span></span></span>
286
+ <span class="sc3"><span class="re1">&lt;/s:for<span class="re2">&gt;</span></span></span>
287
+ <span class="sc3"><span class="re1">&lt;/fn:ShowNames<span class="re2">&gt;</span></span></span>
288
+ ${ShowNames(&quot;beta&quot;)}
289
+ ${ShowNames(&quot;gamma&quot;)}
290
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
291
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
292
+ </div>
293
+ <div id="node-6" class="section-2">
294
+ <h1 class="book-heading">Variables</h1>
295
+ <p><div class="toc">
296
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
297
+ <div class="toc-list">
298
+ <ul>
299
+
300
+ <ul>
301
+
302
+ <ul>
303
+ <li><a href="#Declaringlocalvariables">Declaring local variables</a></li>
304
+ <li><a href="#Declaringglobalvariables">Declaring global variables</a></li>
305
+ <li><a href="#Settinglocalandglobalvalues">Setting local and global values</a></li>
306
+ <li><a href="#Usingviewdata">Using view data</a></li>
307
+ <li><a href="#Usingviewdatawithatypedmodel">Using view data with a typed model</a></li>
308
+ </ul>
309
+ </li>
310
+ </ul>
311
+ </li>
312
+ </ul>
313
+ </div>
314
+ </div></p>
315
+
316
+ <h3 id="Declaringlocalvariables">Declaring local variables</h3>
317
+
318
+ <p>The var element is a quick and easy way to declare local variables. The default behavior is to create a local of automatic type "var" which is initialized inline.</p>
319
+
320
+ <p>For example, the following:</p>
321
+
322
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">styles</span>=<span class="st0">&quot;new [] {'odd', 'even'}&quot;</span> <span class="re0">i</span>=<span class="st0">&quot;0&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
323
+
324
+ <p>Produces the following:</p>
325
+
326
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">var</span> styles <span class="sy0">=</span> <span class="kw3">new</span> <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span><span class="st0">&quot;odd&quot;</span>, <span class="st0">&quot;even&quot;</span><span class="br0">&#125;</span><span class="sy0">;</span>
327
+ <span class="kw4">var</span> i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span></pre></div></p>
328
+
329
+ <p>The var element has an optional type attribute which can be used to provide an explicit type used instead of the automatic type syntax "var".</p>
330
+
331
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">foo</span>=<span class="st0">&quot;null&quot;</span> <span class="re0">bar</span>=<span class="st0">&quot;null&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
332
+
333
+ <p>Will declare variables of type <span class="geshifilter"><code class="geshifilter-xml">string</code></span> instead of <span class="geshifilter"><code class="geshifilter-xml">var</code></span>.</p>
334
+
335
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">string</span> foo <span class="sy0">=</span> null<span class="sy0">;</span>
336
+ <span class="kw4">string</span> bar <span class="sy0">=</span> null<span class="sy0">;</span></pre></div></p>
337
+
338
+ <p>Finally if the var element is not declared as a self-closing tag the scope of the variables will be limited. For example:</p>
339
+
340
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
341
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">styles</span>=<span class="st0">&quot;new [] {'even', 'odd'}&quot;</span> <span class="re0">i</span>=<span class="st0">&quot;0&quot;</span><span class="re2">&gt;</span></span>
342
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${i} is ${styles[i%2]}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
343
+ <span class="sc3"><span class="re1">&lt;/var<span class="re2">&gt;</span></span></span>
344
+ <span class="sc3"><span class="re1">&lt;set</span> <span class="re0">i</span>=<span class="st0">&quot;5&quot;</span><span class="re2">/&gt;</span></span> <span class="sc3"><span class="coMULTI">&lt;!-- compiler error - variable i is out of scope --&gt;</span></span>
345
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
346
+
347
+ <p>will result in:</p>
348
+
349
+ <p><div class="geshifilter"><pre class="geshifilter-csharp">Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;div&gt;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
350
+ <span class="br0">&#123;</span>
351
+ <span class="kw4">var</span> styles<span class="sy0">=</span><span class="kw3">new</span><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span><span class="st0">&quot;even&quot;</span>, <span class="st0">&quot;odd&quot;</span><span class="br0">&#125;</span><span class="sy0">;</span>
352
+ <span class="kw4">var</span> i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span>
353
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;p&gt;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
354
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="sy0">;</span>
355
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot; is &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
356
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>styles<span class="br0">&#91;</span>i<span class="sy0">%</span><span class="nu0">2</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
357
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;/p&gt;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
358
+ <span class="br0">&#125;</span>
359
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;/div&gt;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
360
+ i <span class="sy0">=</span> <span class="nu0">5</span><span class="sy0">;</span></pre></div></p>
361
+
362
+ <p>In this case the local variables are only available inside the <var></var> element. This can be convenient to scope explicitly.</p>
363
+
364
+ <h3 id="Declaringglobalvariables">Declaring global variables</h3>
365
+
366
+ <p>Local variables have a limited scope. They're declared in the generated class right in line in the methods that are generating output. Globals on the other hand can be declared at any location in the view, master, or partial template files and the value can be used and assigned at any point.</p>
367
+
368
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;h2<span class="re2">&gt;</span></span></span>${Title}<span class="sc3"><span class="re1">&lt;/h2<span class="re2">&gt;</span></span></span>
369
+ <span class="sc3"><span class="re1">&lt;global</span> <span class="re0">Title</span>=<span class="st0">&quot;'My Default Title'&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
370
+
371
+ <p>Global variables are actually implemented as field members of the view class. So the above example would contain <span class="geshifilter"><code class="geshifilter-csharp"><span class="kw4">object</span> Title<span class="sy0">=</span><span class="st0">&quot;My Default Title&quot;</span><span class="sy0">;</span></code></span> which is available to from any method. You may also use provide a type attribute to avoid using the default field type object. Multiple variables may be defined in the same element.</p>
372
+
373
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;global</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">Foo</span>=<span class="st0">&quot;'Hello'&quot;</span> <span class="re0">Bar</span>=<span class="st0">&quot;'World'&quot;</span> <span class="re2">/&gt;</span></span></pre></div></p>
374
+
375
+ <h3 id="Settinglocalandglobalvalues">Setting local and global values</h3>
376
+
377
+ <p>The ${expression} and <%=expression%> syntax is only useful for producing a value to send to output. For local and global variable assignment the set element may be used.</p>
378
+
379
+ <p>Using global for title</p>
380
+
381
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
382
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
383
+ <span class="sc3"><span class="re1">&lt;global</span> <span class="re0">type</span>=<span class="st0">'string'</span> <span class="re0">Title</span>=<span class="st0">'&quot;Site Name&quot;'</span><span class="re2">/&gt;</span></span>
384
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${Title}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span>
385
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
386
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
387
+ <span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span><span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
388
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
389
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
390
+
391
+ <p>View that sets the title</p>
392
+
393
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;set</span> <span class="re0">Title</span>=<span class="st0">'product.Name + &quot; - &quot; + Title'</span><span class="re2">/&gt;</span></span>
394
+ <span class="sc3"><span class="coMULTI">&lt;!-- or --&gt;</span></span>
395
+ <span class="sc3"><span class="re1">&lt;set</span> <span class="re0">Title</span>=<span class="st0">'string.Format(&quot;{0} - {1}&quot;, product.Name, Title)'</span><span class="re2">/&gt;</span></span></pre></div></p>
396
+
397
+ <h3 id="Usingviewdata">Using view data</h3>
398
+
399
+ <p>A ViewData property is available as an object dictionary on the base class so syntax like ${ViewData["blah"]} is valid. There is an easier option however which adds a strongly typed property accessor for a view data member.</p>
400
+
401
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
402
+ <span class="re0">Caption</span>=<span class="st0">&quot;string&quot;</span>
403
+ <span class="re0">Products</span>=<span class="st0">&quot;System.Collections.Generic.IList[[MyApp.Models.Product]]&quot;</span><span class="re2">/&gt;</span></span>
404
+ <span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
405
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>${Caption}<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
406
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">each</span>=<span class="st0">&quot;var product in Products&quot;</span><span class="re2">&gt;</span></span>
407
+ <span class="sc3"><span class="re1">&lt;h4<span class="re2">&gt;</span></span></span>${product.Name}<span class="sc3"><span class="re1">&lt;/h4<span class="re2">&gt;</span></span></span>
408
+ <span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>${product.Description}<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
409
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
410
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
411
+
412
+ <p>The viewdata element may occur anywhere in the view or master file actually. The net result is the same which is to add something like the following to the generated class.</p>
413
+
414
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">string</span> Caption
415
+ <span class="br0">&#123;</span>get <span class="br0">&#123;</span><span class="kw1">return</span> <span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#41;</span>ViewData<span class="br0">&#91;</span><span class="st0">&quot;Caption&quot;</span><span class="br0">&#93;</span><span class="sy0">;</span><span class="br0">&#125;</span><span class="br0">&#125;</span>
416
+ &nbsp;
417
+ <span class="kw5">System</span>.<span class="me1">Collections</span>.<span class="me1">Generic</span>.<span class="me1">IList</span><span class="sy0">&lt;</span>MyApp.<span class="me1">Models</span>.<span class="me1">Product</span><span class="sy0">&gt;</span> Products
418
+ <span class="br0">&#123;</span>get <span class="br0">&#123;</span><span class="kw1">return</span> <span class="br0">&#40;</span><span class="kw5">System</span>.<span class="me1">Collections</span>.<span class="me1">Generic</span>.<span class="me1">IList</span><span class="sy0">&lt;</span>MyApp.<span class="me1">Models</span>.<span class="me1">Product</span><span class="sy0">&gt;</span><span class="br0">&#41;</span>ViewData<span class="br0">&#91;</span><span class="st0">&quot;Products&quot;</span><span class="br0">&#93;</span><span class="sy0">;</span><span class="br0">&#125;</span><span class="br0">&#125;</span></pre></div></p>
419
+
420
+ <p>In this case the [[ and ]] are replaced with < and > because of the difficulty xml-centric editors have with certain characters appearing in attributes.</p>
421
+
422
+ <h3 id="Usingviewdatawithatypedmodel">Using view data with a typed model</h3>
423
+
424
+ <p>The viewdata element may have a model attribute in the view or master file.</p>
425
+
426
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">model</span>=<span class="st0">&quot;MyApp.Models.Catalog&quot;</span><span class="re2">/&gt;</span></span>
427
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>(${ViewData.Model.CatalogID}) ${ViewData.Model.Name} <span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span></pre></div></p>
428
+
429
+ <p>The net effect is to have the model attribute used as the TModel parameter for the ViewDataDictionary.</p>
430
+
431
+ <p>The model attribute can be used in conjunction with the other viewdata variable declaration. For example if your master template uses a typecast named viewdata argument to access a member variable, like <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Title</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span></code></span>, your views can still use a specific <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">model</span>=<span class="st0">&quot;typename&quot;</span><span class="re2">/&gt;</span></span></code></span> if the type has a string Title property.</p>
432
+
433
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Title</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span>
434
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${Html.Encode(Title ?? &quot;My Sample MVC Application&quot;)}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span></pre></div></p>
435
+
436
+ <p>The above example enables you to add a string Title property to any class used as a TModel, or as an automatic class <span class="geshifilter"><code class="geshifilter-csharp"><span class="kw3">new</span> <span class="br0">&#123;</span>Title <span class="sy0">=</span> <span class="st0">&quot;hello&quot;</span><span class="br0">&#125;</span></code></span>, or as a dictionary entry in an untyped view data dictionary. </p>
437
+ </div>
438
+ <div id="node-5" class="section-2">
439
+ <h1 class="book-heading">Expressions</h1>
440
+ <div class="toc">
441
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
442
+ <div class="toc-list">
443
+ <ul>
444
+
445
+ <ul>
446
+
447
+ <ul>
448
+ <li><a href="#Simplecsharpexpressions">Simple csharp expressions</a></li>
449
+ <li><a href="#Nullsinexpressions">Nulls in expressions</a></li>
450
+ <li><a href="#UsingMvcHelpers">Using Mvc Helpers</a></li>
451
+ <li><a href="#Conditionalelementsiftestandelse">Conditional elements if, test, and else</a></li>
452
+ <li><a href="#Conditionalattributesifandelseif">Conditional attributes if and elseif</a></li>
453
+ <li><a href="#Conditionalattributeonce">Conditional attribute once</a></li>
454
+ <li><a href="#Conditionalattributeoutput">Conditional attribute output</a></li>
455
+ <li><a href="#Loopinganditeration">Looping and iteration</a></li>
456
+ <li><a href="#Iterationwiththeeachattribute">Iteration with the each attribute</a></li>
457
+ <li><a href="#Usingnamespace">Using namespace</a></li>
458
+ <li><a href="#Inlinecode">Inline code</a></li>
459
+ <li><a href="#DeclaringMacros">Declaring Macros</a></li>
460
+ </ul>
461
+ </li>
462
+ </ul>
463
+ </li>
464
+ </ul>
465
+ </div>
466
+ </div>
467
+
468
+ <h3 id="Simplecsharpexpressions">Simple csharp expressions</h3>
469
+
470
+ <p>Any csharp syntax can appear as ${expression} or <%=expression%></p>
471
+
472
+ <p>The expression text itself is reproduced verbatim as a <span class="geshifilter"><code class="geshifilter-csharp">TextWriter.<span class="me1">Write</span><span class="br0">&#40;</span>expression<span class="br0">&#41;</span><span class="sy0">;</span></code></span> line. So anything that evaluates to a string, simple type, or object with ToString can be used in an expression.</p>
473
+
474
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
475
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>The time is ${DateTime.Now}.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
476
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>The time is <span class="sc3"><span class="re1">&lt;</span>%=DateTime.Now%<span class="re2">&gt;</span></span>.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
477
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
478
+
479
+ <h3 id="Nullsinexpressions">Nulls in expressions</h3>
480
+
481
+ <p>By default when a NullReferenceException is thrown from the <code>${expressions}</code> or <code>&lt;%=expression%&gt;</code> it will be caught and the original expression will be output. This is similar to the behavior you will find in NVelocity and is intended to assist troubleshooting simple data problems.</p>
482
+
483
+ <p>The syntax <code>$!{expression}</code> can also be used if you want to ensure any null values and NullReferenceException that result from the expression will produce no output at all.</p>
484
+
485
+ <p>For example, with the following template:
486
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;shipto&quot;</span><span class="re2">&gt;</span></span>
487
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>$!{currentInvoice.ShipTo.FullName}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
488
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>$!{currentInvoice.ShipTo.Address.City}, $!{currentInvoice.ShipTo.Address.State} $!{currentInvoice.ShipTo.Address.Zip}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
489
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
490
+
491
+ <p>If there is a null <code>currentInvoice</code> or a null <code>ShipTo</code>, the output would be:
492
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;shipto&quot;</span><span class="re2">&gt;</span></span>
493
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
494
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>, <span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
495
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
496
+
497
+ <p>It's not ideal by a long shot, but slightly better than a yellow screen of death if you don't manage to get a hundred percent correct null testing in your views.</p>
498
+
499
+ <h3 id="UsingMvcHelpers">Using Mvc Helpers</h3>
500
+
501
+ <p>There are instances of HtmlHelper, UrlHelper, and AjaxHelper available as Html, Url, and Ajax properties respectively. Any of their methods which return string-friendly information can be used as an output expressions.</p>
502
+
503
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="coMULTI">&lt;!-- Link to the Sort action on the current controller --&gt;</span></span>
504
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${Html.ActionLink(&quot;Click me&quot;, &quot;Sort&quot;)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
505
+ <span class="sc3"><span class="coMULTI">&lt;!-- Put out data in a way that's safe --&gt;</span></span>
506
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${Html.Encode(stuff)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span></pre></div></p>
507
+
508
+ <h3 id="Conditionalelementsiftestandelse">Conditional elements if, test, and else</h3>
509
+
510
+ <p>The elements &lt;if&gt; and &lt;else&gt; can be used to produce content conditionally. The if element must have a condition attribute which is used literally as the boolean csharp expression.</p>
511
+
512
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">x</span>=<span class="st0">'5'</span><span class="re2">/&gt;</span></span>
513
+ &nbsp;
514
+ <span class="sc3"><span class="re1">&lt;if</span> <span class="re0">condition</span>=<span class="st0">'x == 5'</span><span class="re2">&gt;</span></span>
515
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">class</span>=<span class="st0">'resultmessage'</span><span class="re2">&gt;</span></span>Some value is five<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
516
+ <span class="sc3"><span class="re1">&lt;/if<span class="re2">&gt;</span></span></span></pre></div></p>
517
+
518
+ <p>An &lt;if&gt; element may be followed by any number of optional &lt;else&gt; elements that have if attributes and finally a single, optional &lt;else&gt; element. Only whitespace may be between the if/else elements.</p>
519
+
520
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">user</span>=<span class="st0">'UserInfo'</span><span class="re2">/&gt;</span></span>
521
+ &nbsp;
522
+ <span class="sc3"><span class="re1">&lt;if</span> <span class="re0">condition</span>=<span class="st0">'!user.IsLoggedIn()'</span><span class="re2">&gt;</span></span>
523
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Here's a login form<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
524
+ <span class="sc3"><span class="re1">&lt;/if<span class="re2">&gt;</span></span></span>
525
+ <span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">'user.HasRole(RoleType.Administrator)'</span><span class="re2">&gt;</span></span>
526
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello - you're an admin<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
527
+ <span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span>
528
+ <span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">'user.HasRole(RoleType.Registered)'</span><span class="re2">&gt;</span></span>
529
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello - you're a registered user<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
530
+ <span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span>
531
+ <span class="sc3"><span class="re1">&lt;else<span class="re2">&gt;</span></span></span>
532
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>I have no idea what type of person you are<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
533
+ <span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span></pre></div></p>
534
+
535
+ <p>If you prefer, instread of &lt;if condition=""&gt; you can use the &lt;test if=""&gt; syntax. The functionality is the same. Another variation on the syntax is the ability to use empty &lt;else if=""/&gt; and &lt;else/&gt; elements inside of the <if> or <test>. The following identical to the example above.</p>
536
+
537
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">user</span>=<span class="st0">'UserInfo'</span><span class="re2">/&gt;</span></span>
538
+ &nbsp;
539
+ <span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">'!user.IsLoggedIn()'</span><span class="re2">&gt;</span></span>
540
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Here's a login form<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
541
+ <span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">'user.HasRole(RoleType.Administrator)'</span><span class="re2">/&gt;</span></span>
542
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello - you're an admin<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
543
+ <span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">'user.HasRole(RoleType.Registered)'</span><span class="re2">/&gt;</span></span>
544
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello - you're a registered user<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
545
+ <span class="sc3"><span class="re1">&lt;else</span><span class="re2">/&gt;</span></span>
546
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>I have no idea what type of person you are<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
547
+ <span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span></pre></div></p>
548
+
549
+ <h3 id="Conditionalattributesifandelseif">Conditional attributes if and elseif</h3>
550
+
551
+ <p>The if and elseif attributes can be used on any other element. This has the same effect as having a wrapping if or else element.</p>
552
+
553
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">x</span>=<span class="st0">'5'</span><span class="re2">/&gt;</span></span>
554
+ &nbsp;
555
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">if</span>=<span class="st0">'x==5'</span> <span class="re0">class</span>=<span class="st0">'resultmessage'</span><span class="re2">&gt;</span></span>Some value is five<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span></pre></div></p>
556
+
557
+ <p>The same rules about order and whitespace apply. An element with an elseif="" attribute, or an else element, may only follow another conditional element.</p>
558
+
559
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">namespace</span>=<span class="st0">'SampleApp.Models'</span><span class="re2">/&gt;</span></span>
560
+ <span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">user</span>=<span class="st0">'UserInfo'</span><span class="re2">/&gt;</span></span>
561
+ &nbsp;
562
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">if</span>=<span class="st0">'!user.IsLoggedIn()'</span><span class="re2">&gt;</span></span>Here's a login form<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
563
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">elseif</span>=<span class="st0">'user.HasRole(RoleType.Administrator)'</span><span class="re2">&gt;</span></span>Hello - you're an admin<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
564
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">elseif</span>=<span class="st0">'user.HasRole(RoleType.Registered)'</span><span class="re2">&gt;</span></span>Hello - you're a registered user<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
565
+ <span class="sc3"><span class="re1">&lt;else<span class="re2">&gt;</span></span></span>
566
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>I have no idea what type of person you are<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
567
+ <span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span></pre></div></p>
568
+
569
+ <h3 id="Conditionalattributeonce">Conditional attribute once</h3>
570
+
571
+ <p>A fairly typical situation can come up where a partial will need to add a stylesheet reference or some jquery code. On the one hand you don't want to have those resources pulled in multiple times if the partial is used more than once, and on the other hand you don't want to simply include that resource just once in the site layout for all pages whether they need it or not. One way to implement the middle ground is to declare a boolean flag and set it once when you add a script to the header.</p>
572
+
573
+ <p>To make this code smaller the attribute <span class="geshifilter"><code class="geshifilter-xml">once=&quot;flagname&quot;</code></span> was added. The contents of the element will be rendered only the first time any given "flagname" values is used when rendering a page. Any conventions can be used about what values are used as flags, the following is just an example. You may also use ${expr} or <%=expr%> syntax in the value of the once attribute.</p>
574
+
575
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">name</span>=<span class="st0">&quot;head&quot;</span><span class="re2">&gt;</span></span>
576
+ <span class="sc3"><span class="coMULTI">&lt;!-- add jquery if it hasn't been yet, and add countdown plugin --&gt;</span></span>
577
+ <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">once</span>=<span class="st0">&quot;jquery&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;~/content/js/jquery-1.2.6.js&quot;</span><span class="re2">/&gt;</span></span>
578
+ <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">once</span>=<span class="st0">&quot;jquery-countdown&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;~/content/js/jquery.countdown.js&quot;</span><span class="re2">/&gt;</span></span>
579
+ <span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span></pre></div></p>
580
+
581
+ <p>The implementation if this attribute results in the <span class="geshifilter"><code class="geshifilter-xml">bool Once(string flagname)</code></span> method being called which returns true the first time a distinct value is used for the argument. This method may also be called from code.</p>
582
+
583
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;macro</span> <span class="re0">name</span>=<span class="st0">&quot;Peculiar&quot;</span> <span class="re0">issue</span>=<span class="st0">&quot;string&quot;</span><span class="re2">&gt;</span></span>
584
+ #if (Once(&quot;log-peculiar&quot;))
585
+ # Logger.Warn(&quot;Something's not right on this page. First issue: &quot; + issue);
586
+ <span class="sc3"><span class="re1">&lt;/macro<span class="re2">&gt;</span></span></span></pre></div></p>
587
+
588
+ <h3 id="Conditionalattributeoutput">Conditional attribute output</h3>
589
+
590
+ <p>The syntax <code>?{boolean}</code> can be used only inside the text of an attribute. Text and code before the condition (up to and including the previous whitespace) will be controlled by the result of the boolean expression. In the generated code the boolean will appear directly inside the parenthesis of an if statement, so anything that evaluates to a bool is okay.</p>
591
+
592
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
593
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;var product in Products&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;first?{productIsFirst} last?{productIsLast}&quot;</span><span class="re2">&gt;</span></span>
594
+ ${H(product.Name)}
595
+ <span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
596
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
597
+
598
+ <p>will output</p>
599
+
600
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
601
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">class</span>=<span class="st0">&quot;first&quot;</span><span class="re2">&gt;</span></span>Alpha<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
602
+ <span class="sc3"><span class="re1">&lt;li<span class="re2">&gt;</span></span></span>Beta<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
603
+ <span class="sc3"><span class="re1">&lt;li<span class="re2">&gt;</span></span></span>Gamma<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
604
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">class</span>=<span class="st0">&quot; last&quot;</span><span class="re2">&gt;</span></span>Delta<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
605
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span>
606
+ or
607
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
608
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">class</span>=<span class="st0">&quot;first last&quot;</span><span class="re2">&gt;</span></span>just one product<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
609
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
610
+
611
+ <p>Plus if all of the text of an attribute is killed, or if the only thing in the attribute was the test, then the entire attribute will disappear from the output. That's for checkboxes and such.</p>
612
+
613
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;checkbox&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;chkhello&quot;</span> <span class="re0">checked</span>=<span class="st0">&quot;?{isHelloChecked}&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;/input<span class="re2">&gt;</span></span></span></pre></div></p>
614
+
615
+ <p>will output</p>
616
+
617
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;checkbox&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;chkhello&quot;</span> <span class="re0">checked</span>=<span class="st0">&quot;&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;/input<span class="re2">&gt;</span></span></span>
618
+ or
619
+ <span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;checkbox&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;chkhello&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;/input<span class="re2">&gt;</span></span></span></pre></div></p>
620
+
621
+ <h3 id="Loopinganditeration">Looping and iteration</h3>
622
+
623
+ <p>A foreach loop is produced with the element for and the attribute each. The each attribute is used verbatim so must have the type, variable name, "in", and collection.</p>
624
+
625
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Posts</span>=<span class="st0">&quot;IList[[MyApp.Models.Post]&quot;</span><span class="re2">/&gt;</span></span>
626
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var post in Posts&quot;</span><span class="re2">&gt;</span></span>
627
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${post.Title}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
628
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></pre></div></p>
629
+
630
+ <p>Any for loop comes with several optional local variables. Their name is always the same as the looping variable, plus the suffixes "Index", "Count", "IsFirst", and "IsLast". The variables are scoped to the for loop itself, and only the ones which appear to be used in the contained code will be created.</p>
631
+
632
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Posts</span>=<span class="st0">&quot;IList[[MyApp.Models.Post]&quot;</span><span class="re2">/&gt;</span></span>
633
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">styles</span>=<span class="st0">&quot;new[] {'even','odd'}&quot;</span><span class="re2">/&gt;</span></span>
634
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var post in Posts&quot;</span><span class="re2">&gt;</span></span>
635
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">class</span>=<span class="st0">&quot;${styles[postIndex%2]}&quot;</span><span class="re2">&gt;</span></span>${postIndex}. ${post.Title}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
636
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></pre></div></p>
637
+
638
+ <p>Something to be aware with the use of the "Count" and "IsLast" variables - they both need to know how many items are in the collection before the iteration begins. For collections that resolve to IEnumerable&lt;T&gt; the Linq extension method .Count() is used, and for plain old IEnumerable Spark will run iterate the collection incrementing an integer to get the count. Not a performance problem of course, just worth mentioning.</p>
639
+
640
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var lineItem in CurrentInvoice.LineItems&quot;</span><span class="re2">&gt;</span></span>
641
+ <span class="sc3"><span class="re1">&lt;tr<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>Item ${lineItemIndex} of ${lineItemCount}<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>${lineItem.Etc}<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span>
642
+ <span class="sc3"><span class="re1">&lt;tr</span> <span class="re0">if</span>=<span class="st0">&quot;${lineItemIsLast}&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>Grand total<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>etc<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span>
643
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></pre></div></p>
644
+
645
+ <p>The for element can also have additional attributes which will evaluated as a variable assignment. Note - the named variable of the correct type must already exist. <em>Maybe at some point the code generator will keep track of declared variables in scope and create new 'var's where appropriate. I think I'll add a trac item for that.</em></p>
646
+
647
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">currentProductId</span>=<span class="st0">&quot;int&quot;</span><span class="re2">/&gt;</span></span>
648
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">styles</span>=<span class="st0">&quot;new [] {'even', 'odd'}&quot;</span> <span class="re0">isCurrent</span>=<span class="st0">&quot;false&quot;</span><span class="re2">&gt;</span></span>
649
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var product in Products&quot;</span> <span class="re0">isCurrent</span>=<span class="st0">&quot;product.Id==currentProductId&quot;</span><span class="re2">&gt;</span></span>
650
+ <span class="sc3"><span class="re1">&lt;p</span> <span class="re0">class</span>=<span class="st0">&quot;highlighted?{isCurrent} ${styles[productIndex%2]}&quot;</span><span class="re2">&gt;</span></span>${Html.Encode(product.Name)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
651
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span>
652
+ <span class="sc3"><span class="re1">&lt;/var<span class="re2">&gt;</span></span></span></pre></div></p>
653
+
654
+ <h3 id="Iterationwiththeeachattribute">Iteration with the each attribute</h3>
655
+
656
+ <p>You may also add the each attribute to any plain element.</p>
657
+
658
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;table<span class="re2">&gt;</span></span></span>
659
+ <span class="sc3"><span class="re1">&lt;tr<span class="re2">&gt;</span></span></span>
660
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>Name<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
661
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>Type<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
662
+ <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span>
663
+ <span class="sc3"><span class="re1">&lt;tr</span> <span class="re0">each</span>=<span class="st0">'var user in users'</span><span class="re2">&gt;</span></span>
664
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>${user.Name}<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
665
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>${user.UserType}<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
666
+ <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span>
667
+ <span class="sc3"><span class="re1">&lt;/table<span class="re2">&gt;</span></span></span></pre></div></p>
668
+
669
+ <p>If you do that other attributes are not treated as variable assignment, but they may contain ${expression} evaluation.</p>
670
+
671
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;table<span class="re2">&gt;</span></span></span>
672
+ <span class="sc3"><span class="re1">&lt;tr<span class="re2">&gt;</span></span></span>
673
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>Name<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
674
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>Type<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
675
+ <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span>
676
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">classes</span>=<span class="st0">&quot;new [] {'even','odd'}&quot;</span><span class="re2">&gt;</span></span>
677
+ <span class="sc3"><span class="re1">&lt;tr</span> <span class="re0">each</span>=<span class="st0">&quot;var user in users&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;${classes[userIndex%2]}&quot;</span><span class="re2">&gt;</span></span>
678
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>${userIndex}) ${user.Name}<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
679
+ <span class="sc3"><span class="re1">&lt;td<span class="re2">&gt;</span></span></span>${user.UserType}<span class="sc3"><span class="re1">&lt;/td<span class="re2">&gt;</span></span></span>
680
+ <span class="sc3"><span class="re1">&lt;/tr<span class="re2">&gt;</span></span></span>
681
+ <span class="sc3"><span class="re1">&lt;/var<span class="re2">&gt;</span></span></span>
682
+ <span class="sc3"><span class="re1">&lt;/table<span class="re2">&gt;</span></span></span></pre></div></p>
683
+
684
+ <h3 id="Usingnamespace">Using namespace</h3>
685
+
686
+ <p>You can add using statements to avoid typing out fully qualified type names, and to make extension methods to helpers available.</p>
687
+
688
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">namespace</span>=<span class="st0">&quot;System.Collections.Generic&quot;</span><span class="re2">/&gt;</span></span>
689
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">namespace</span>=<span class="st0">&quot;System.Web.Mvc&quot;</span><span class="re2">/&gt;</span></span>
690
+ <span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Names</span>=<span class="st0">&quot;IList[[string]]&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
691
+
692
+ <p>The use namespace elements may appear anywhere in the view, master, or partial template files. The namespaces are de-duplicated so it's safe to include them where they're needed in views and partials if you prefer even though the same namespace could appear several times.</p>
693
+
694
+ <h3 id="Inlinecode">Inline code</h3>
695
+
696
+ <p>Sometimes, when push comes to shove, you have a situation where you're not writing output and there isn't a markup construct for what you want to do. As a last resort you can produce code directly in-place in the generated class.</p>
697
+
698
+ <p>This takes two forms. An aspx-like <%statement%> version is available as well as a #statement<end-of-line> variation.</p>
699
+
700
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">&quot;user.IsLoggedIn()&quot;</span><span class="re2">&gt;</span></span>
701
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello, ${user.Name}.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
702
+ <span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">&quot;user.HasValidTrialSession()&quot;</span><span class="re2">/&gt;</span></span>
703
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello, Valued Future Customer.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
704
+ <span class="sc3"><span class="re1">&lt;else</span><span class="re2">/&gt;</span></span>
705
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Hello, er... you.<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
706
+ # System.Diagnostic.Trace.WriteLine(&quot;Unexpected anon user.&quot;);
707
+ # if (System.Diagnostic.Debugger.IsAttached)
708
+ # System.Diagnostic.Debugger.Break();
709
+ <span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span></pre></div></p>
710
+
711
+ <h3 id="DeclaringMacros">Declaring Macros</h3>
712
+
713
+ <p>When it comes right down to it a helper method is a function that takes arguments and returns a string. A Spark &lt;macro&gt; produces something which is much the same: a function that takes arguments and returns a string.</p>
714
+
715
+ <p>Because a macro is declared in a the spark template it's contents may contain any literal html, rendering of partial files, expression evaluation, etc. All of the output from this is captured as the simple return value. This enables you to invoke a &lt;macro name="foo"&gt; using ${foo()} or &lt;%=foo()%&gt; from anywhere in your template files.</p>
716
+
717
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">errorMessage</span>=<span class="st0">&quot;string&quot;</span> <span class="re2">/&gt;</span></span>
718
+ &nbsp;
719
+ <span class="sc3"><span class="re1">&lt;macro</span> <span class="re0">name</span>=<span class="st0">&quot;ShowError&quot;</span> <span class="re0">caption</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">message</span>=<span class="st0">&quot;string&quot;</span><span class="re2">&gt;</span></span>
720
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;message error&quot;</span><span class="re2">&gt;</span></span>
721
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>${H(caption)}<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
722
+ <span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>${message}<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
723
+ <span class="sc3"><span class="re1">&lt;</span>% Logger.Warn<span class="br0">&#40;</span>caption<span class="br0">&#41;</span>; %<span class="re2">&gt;</span></span> <span class="sc3"><span class="coMULTI">&lt;!-- this is a MR example. asp.net mvc would use different logging --&gt;</span></span>
724
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
725
+ <span class="sc3"><span class="re1">&lt;/macro<span class="re2">&gt;</span></span></span>
726
+ &nbsp;
727
+ <span class="sc3"><span class="re1">&lt;h2<span class="re2">&gt;</span></span></span>Place Order<span class="sc3"><span class="re1">&lt;/h2<span class="re2">&gt;</span></span></span>
728
+ <span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">&quot;!string.IsNullOrEmpty(errorMessage)&quot;</span><span class="re2">&gt;</span></span>
729
+ ${ShowError(&quot;Failed to place order&quot;, errorMessage)}
730
+ <span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span>
731
+ &nbsp;
732
+ <span class="sc3"><span class="coMULTI">&lt;!-- form here, field validation messages, etc. --&gt;</span></span></pre></div></p>
733
+
734
+ <p>The following method generated code is the result</p>
735
+
736
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">string</span> ShowError<span class="br0">&#40;</span><span class="kw4">string</span> caption, <span class="kw4">string</span> message<span class="br0">&#41;</span>
737
+ <span class="br0">&#123;</span>
738
+ <span class="kw1">using</span><span class="br0">&#40;</span>OutputScope<span class="br0">&#40;</span><span class="kw3">new</span> <span class="kw5">System</span>.<span class="me1">IO</span>.<span class="me1">StringWriter</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
739
+ <span class="br0">&#123;</span>
740
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es0">\r</span><span class="es0">\n</span> &lt;div class=<span class="es0">\&quot;</span>message error<span class="es0">\&quot;</span>&gt;<span class="es0">\r</span><span class="es0">\n</span> &lt;h3&gt;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
741
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>H<span class="br0">&#40;</span>caption<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
742
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;/h3&gt;<span class="es0">\r</span><span class="es0">\n</span> &lt;div&gt;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
743
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>message<span class="br0">&#41;</span><span class="sy0">;</span>
744
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;/div&gt;<span class="es0">\r</span><span class="es0">\n</span> &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
745
+ Logger.<span class="me1">Warn</span><span class="br0">&#40;</span>caption<span class="br0">&#41;</span><span class="sy0">;</span>
746
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot; &lt;/div&gt;<span class="es0">\r</span><span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
747
+ <span class="kw1">return</span> Output.<span class="me1">ToString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
748
+ <span class="br0">&#125;</span>
749
+ <span class="br0">&#125;</span>
750
+ &nbsp;
751
+ <span class="co1">//... and in the RenderViewContent method</span>
752
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es0">\r</span><span class="es0">\n</span>&lt;h2&gt;Place Order&lt;/h2&gt;<span class="es0">\r</span><span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
753
+ <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw4">string</span>.<span class="me1">IsNullOrEmpty</span><span class="br0">&#40;</span>errorMessage<span class="br0">&#41;</span><span class="br0">&#41;</span>
754
+ <span class="br0">&#123;</span>
755
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>ShowError<span class="br0">&#40;</span><span class="st0">&quot;Failed to place order&quot;</span>, errorMessage<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
756
+ <span class="br0">&#125;</span> <span class="co1">// if (!string.IsNullOrEmpty(errorMessage))</span>
757
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es0">\r</span><span class="es0">\n</span><span class="es0">\r</span><span class="es0">\n</span>&lt;!-- form here, field validation messages, etc. --&gt;<span class="es0">\r</span><span class="es0">\n</span><span class="es0">\r</span><span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
758
+
759
+ <p>A macro may also call itself recursively, which is convenient for producing something like a threaded comment list or a nested ul/ul/li tree structure.</p>
760
+ </div>
761
+ <div id="node-34" class="section-2">
762
+ <h1 class="book-heading">Master Layouts</h1>
763
+ <div class="toc">
764
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
765
+ <div class="toc-list">
766
+ <ul>
767
+
768
+ <ul>
769
+
770
+ <ul>
771
+ <li><a href="#Preface">Preface</a></li>
772
+ <li><a href="#Howmasterlayoutfileswork">How master-layout files work</a></li>
773
+ <li><a href="#SelectingLayout">Selecting Layout</a></li>
774
+ <li><a href="#Threepassrendering">Three pass rendering</a></li>
775
+ </ul>
776
+ </li>
777
+ </ul>
778
+ </li>
779
+ </ul>
780
+ </div>
781
+ </div>
782
+
783
+ <h3 id="Preface">Preface</h3>
784
+
785
+ <p>This entire subject is ASP.NET MVC specific. MonoRail has it's own mechanism for selecting layout files, and Spark works in that context as expected.</p>
786
+
787
+ <h3 id="Howmasterlayoutfileswork">How master-layout files work</h3>
788
+
789
+ <p>When a view is rendered with a master layout template selected Spark renders the view in a multiple passes. The first pass will render the contents of the view template from the top down. The output of that pass is captured in a content variable named "view".</p>
790
+
791
+ <p>The second pass will render the contents of the master template from the top down. The master template will contain <code>&lt;use content="view"/&gt;</code> or <code>&lt;use:view/&gt;</code> at the location where the view content should appear.</p>
792
+
793
+ <p><strong>Application.spark</strong>
794
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
795
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
796
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${Title}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span>
797
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
798
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
799
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;header&quot;</span><span class="re2">&gt;</span></span>dot dot dot<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
800
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;pageContent&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span><span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
801
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;footer&quot;</span><span class="re2">&gt;</span></span>dot dot dot<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
802
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
803
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
804
+
805
+ <p>From the master template's perpective the "view" is just a piece of named content.</p>
806
+
807
+ <h3 id="SelectingLayout">Selecting Layout</h3>
808
+
809
+ <p>There are several ways to select a which master layout file should be used. The following are the ways a template may be selected, from weakest to strongest.</p>
810
+
811
+ <ul>
812
+ <li>An Application.spark file in the Views/Layouts folder or Views/Shared folder</li>
813
+ </ul>
814
+
815
+ <p>This is the most general-purpose way to have a site-wide master template. It will not be used if the controller returns a PartialView().</p>
816
+
817
+ <ul>
818
+ <li>A .spark file in Views/Layouts or Views/Shared with the same name as the controller</li>
819
+ </ul>
820
+
821
+ <p>For example if you have an AccountController you could have a Views/Layouts/Account.spark file which is used on that controller, but all other controllers use the Views/Layouts/Application.spark template.</p>
822
+
823
+ <ul>
824
+ <li>Naming the master layout as the second argument when you return a View() as the ActionResult</li>
825
+ </ul>
826
+
827
+ <p>This gives the selection of layout to the controller, which some people may believe isn't necessarily a concern for the controller. What'cha gonna do? If this is present it will override the first two conventions.</p>
828
+
829
+ <ul>
830
+ <li>Naming the master layout as an <code>&lt;use master=""/&gt;</code> element in the view.</li>
831
+ </ul>
832
+
833
+ <p>This is actually the strongest mechanism available for wrapping a view in a layout file. It will override the conventional forms of master selection, and it will cause the name of the master in the View() ActionResult to be ignored if it's present.</p>
834
+
835
+ <p>Interestingly, it may also be used in the layout files themselves to establish three or more pass rendering.</p>
836
+
837
+ <h3 id="Threepassrendering">Three pass rendering</h3>
838
+
839
+ <p>Three pass rendering can be used to address a common problem. The cause isn't always obvious, especially if you're new to the named-content top-down rendering technique.</p>
840
+
841
+ <p>The problem is this. Let's say you're using a named content section, like "head" or "nav", at the top of your master layout file. Then you add some partials in the sidebar or other places in the layout that add script and stylesheet references to the "head" content. The problem you'll encounter is that the "head" is actually written to the output stream before those bits further down the layout execute and add those resources to the named content.</p>
842
+
843
+ <p><strong>Views/Layouts/Application.spark</strong>
844
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
845
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
846
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;head&quot;</span><span class="re2">/&gt;</span></span>
847
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
848
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
849
+ <span class="sc3"><span class="re1">&lt;Header</span><span class="re2">/&gt;</span></span>
850
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span>
851
+ <span class="sc3"><span class="re1">&lt;Sidebar</span><span class="re2">/&gt;</span></span>
852
+ <span class="sc3"><span class="re1">&lt;Footer</span><span class="re2">/&gt;</span></span>
853
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;tail&quot;</span><span class="re2">/&gt;</span></span>
854
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
855
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
856
+
857
+ <p><strong>Views/Shared/_Sidebar.spark</strong>
858
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">name</span>=<span class="st0">&quot;head&quot;</span><span class="re2">&gt;</span></span>
859
+ <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">src</span>=<span class="st0">&quot;~/content/js/jquery-ui-accordian.js&quot;</span> <span class="re0">once</span>=<span class="st0">&quot;jquery-accordian&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
860
+ <span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span>
861
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;sidebar&quot;</span><span class="re2">&gt;</span></span>etc<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
862
+
863
+ <p>One way to use three-pass rendering to solve this problem would be to create a super-layout named <code>Html.spark</code>, and for the master file <code>Application.spark</code> to wrap itself in that layout. Note that from the <code>Html.spark</code> file's perspective the entire output of the <code>Application.spark</code>, and the view which it encloses, is contained in the "view" named content.</p>
864
+
865
+ <p><strong>Views/Layouts/Html.spark</strong>
866
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
867
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
868
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;head&quot;</span><span class="re2">/&gt;</span></span>
869
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
870
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
871
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span>
872
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;tail&quot;</span><span class="re2">/&gt;</span></span>
873
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
874
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
875
+
876
+ <p><strong>Views/Layouts/Application.spark</strong>
877
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">master</span>=<span class="st0">&quot;Html&quot;</span><span class="re2">/&gt;</span></span>
878
+ &nbsp;
879
+ <span class="sc3"><span class="re1">&lt;Header</span><span class="re2">/&gt;</span></span>
880
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span>
881
+ <span class="sc3"><span class="re1">&lt;Sidebar</span><span class="re2">/&gt;</span></span>
882
+ <span class="sc3"><span class="re1">&lt;Footer</span><span class="re2">/&gt;</span></span></pre></div></p>
883
+ </div>
884
+ <div id="node-7" class="section-2">
885
+ <h1 class="book-heading">Organizing Content</h1>
886
+ <p><div class="toc">
887
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
888
+ <div class="toc-list">
889
+ <ul>
890
+
891
+ <ul>
892
+
893
+ <ul>
894
+ <li><a href="#MasterViewrelationship">Master-View relationship</a></li>
895
+ <li><a href="#Namedcontentsections">Named content sections</a></li>
896
+ <li><a href="#Parsingandrenderingpartialfiles">Parsing and rendering partial files</a></li>
897
+ <li><a href="#Implicitpartialrendering">Implicit partial rendering</a></li>
898
+ <li><a href="#Importingfiles">Importing files</a></li>
899
+ <li><a href="#Includingfiles">Including files</a></li>
900
+ </ul>
901
+ </li>
902
+ </ul>
903
+ </li>
904
+ </ul>
905
+ </div>
906
+ </div></p>
907
+
908
+ <h3 id="MasterViewrelationship">Master-View relationship</h3>
909
+
910
+ <p>The view contents are rendered first, followed by the master contents. The master template includes the view at the appropriate location with ${Content["view"]}, or <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span></code></span>, or <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use:view</span><span class="re2">/&gt;</span></span></code></span>.</p>
911
+
912
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
913
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
914
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${Title}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span>
915
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
916
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
917
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;header&quot;</span><span class="re2">&gt;</span></span>dot dot dot<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
918
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;pageContent&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span><span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
919
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;footer&quot;</span><span class="re2">&gt;</span></span>dot dot dot<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
920
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
921
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
922
+
923
+ <h3 id="Namedcontentsections">Named content sections</h3>
924
+
925
+ <p>Defining additional number of content sections or modules is one way you can create extensible blocks or regions in your layout. It's also a convenient way to enable a view to include additional css and js references in the head section.</p>
926
+
927
+ <p>This example shows a master layout which provides the ability for the views to add script and style to the head element, and add sections to a sidebar container.</p>
928
+
929
+ <p>Making named content appear in output</p>
930
+
931
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
932
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
933
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${Title}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span>
934
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;head&quot;</span><span class="re2">/&gt;</span></span>
935
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
936
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
937
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;header&quot;</span><span class="re2">&gt;</span></span>dot dot dot<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
938
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;sidebar&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;sidebar&quot;</span><span class="re2">/&gt;</span></span><span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
939
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;pageContent&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;view&quot;</span><span class="re2">/&gt;</span></span><span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
940
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;footer&quot;</span><span class="re2">&gt;</span></span>dot dot dot<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
941
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
942
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
943
+
944
+ <p>Adding information to named content locations</p>
945
+
946
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>this goes in the pageContent<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
947
+ &nbsp;
948
+ <span class="sc3"><span class="re1">&lt;content</span> <span class="re0">name</span>=<span class="st0">&quot;sidebar&quot;</span><span class="re2">&gt;</span></span>
949
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>Search<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
950
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>This is added to the sidebar<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
951
+ <span class="sc3"><span class="re1">&lt;content<span class="re2">&gt;</span></span></span>
952
+ &nbsp;
953
+ <span class="sc3"><span class="re1">&lt;content</span> <span class="re0">name</span>=<span class="st0">&quot;head&quot;</span><span class="re2">&gt;</span></span>
954
+ <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;yadda/file.js&quot;</span><span class="re2">&gt;</span></span><span class="sc3"><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
955
+ <span class="sc3"><span class="re1">&lt;content<span class="re2">&gt;</span></span></span>
956
+ &nbsp;
957
+ <span class="sc3"><span class="re1">&lt;content</span> <span class="re0">name</span>=<span class="st0">&quot;sidebar&quot;</span><span class="re2">&gt;</span></span>
958
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>See also<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
959
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>This is also added to the sidebar<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
960
+ <span class="sc3"><span class="re1">&lt;content<span class="re2">&gt;</span></span></span></pre></div></p>
961
+
962
+ <p>The implementation details of this are very straightforward. The generated class is appending values to the current textwriter. When a <content name="foo"> element is encountered it changes which textwriter is current. Later when a &lt;use content="foo"/&gt; or ${Content["foo"]} is encountered the accumulated text in the named content is written to the textwriter that is current at the time. </p>
963
+
964
+ <p>There is one intrinsic content section named "view". It will contain the output of the previous level when rendering view/master. In MonoRail there can be several layouts named, and the section named "view" will always contain the total result of the previous levels.</p>
965
+
966
+ <p>You can also use the prefixes as an alias for &lt;content name="foo"&gt; and &lt;use content="foo"&gt;. Those would be content:foo and use:foo respectively.</p>
967
+
968
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content:message<span class="re2">&gt;</span></span></span>
969
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>This is a message<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
970
+ <span class="sc3"><span class="re1">&lt;/content:message<span class="re2">&gt;</span></span></span>
971
+ &nbsp;
972
+ <span class="sc3"><span class="re1">&lt;content:message<span class="re2">&gt;</span></span></span>
973
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>This is another message<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
974
+ <span class="sc3"><span class="re1">&lt;/content:message<span class="re2">&gt;</span></span></span>
975
+ &nbsp;
976
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;messages&quot;</span> <span class="re0">if</span>=<span class="st0">&quot;Content.ContainsKey('message')&quot;</span><span class="re2">&gt;</span></span>
977
+ <span class="sc3"><span class="re1">&lt;use:message</span><span class="re2">/&gt;</span></span>
978
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
979
+
980
+ <h3 id="Parsingandrenderingpartialfiles">Parsing and rendering partial files</h3>
981
+
982
+ <p>You can include and render a partial file at a particular location with the following syntax:</p>
983
+
984
+ <p>viewfile</p>
985
+
986
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">file</span>=<span class="st0">&quot;mypartial&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
987
+
988
+ <p>This will look for a mypartial.xml file in the same directory as the view or in the Shared directory.</p>
989
+
990
+ <p>You can also declare local variables as attributes of the "use" element. Those variables, and anything else that was in context, can be used within the scope of the partial as local variables.</p>
991
+
992
+ <p>viewfile</p>
993
+
994
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">file</span>=<span class="st0">&quot;mypartial&quot;</span> <span class="re0">caption</span>=<span class="st0">&quot;product.Name&quot;</span><span class="re2">/&gt;</span></span></pre></div></p>
995
+
996
+ <p>mypartial.xml</p>
997
+
998
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
999
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>${caption}<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
1000
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
1001
+
1002
+ <h3 id="Implicitpartialrendering">Implicit partial rendering</h3>
1003
+
1004
+ <p>Finally, if your partial file starts with an underscore character the rest of the file name can be used as a new special element. This is nothing more than <specialname/> being used as a shortcut for <use file="_specialname"/> but it sure looks cool.</p>
1005
+
1006
+ <p>viewfile</p>
1007
+
1008
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">styles</span>=<span class="st0">'new[] {&quot;even&quot;, &quot;odd&quot;}'</span> <span class="re0">i</span>=<span class="st0">'0'</span><span class="re2">&gt;</span></span>
1009
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">'var product in Products'</span> <span class="re0">i</span>=<span class="st0">'i+1'</span><span class="re2">&gt;</span></span>
1010
+ <span class="sc3"><span class="re1">&lt;ProductSummary</span> <span class="re0">cssclass</span>=<span class="st0">&quot;styles[i%2]&quot;</span> <span class="re0">number</span>=<span class="st0">&quot;i&quot;</span><span class="re2">/&gt;</span></span>
1011
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span>
1012
+ <span class="sc3"><span class="re1">&lt;/var<span class="re2">&gt;</span></span></span></pre></div></p>
1013
+
1014
+ <p>_ProductSummary.xml</p>
1015
+
1016
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;${cssclass}&quot;</span><span class="re2">&gt;</span></span>
1017
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${number}) ${product.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1018
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
1019
+
1020
+ <p>Partial files starting with an underscore will be used from the view directory of the controller and from the "Shared" view directory. </p>
1021
+
1022
+ <h3 id="Importingfiles">Importing files</h3>
1023
+
1024
+ <p>Many of the elements like &lt;global&gt;, &lt;viewdata&gt;, &lt;macro name=""&gt;, &lt;use namespace=""&gt;, and &lt;use assembly=""&gt; have an effect on the generated view class but do not produce output in-line.</p>
1025
+
1026
+ <p>You can remove a lot of these declarations from view, partial, and layout files by moving them into a spark file which you then import. </p>
1027
+
1028
+ <p><b>Shared\\CommonMacros.spark</b><br />
1029
+ <div class="geshifilter"><pre class="geshifilter-xml">General-purpose references
1030
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">namespace</span>=<span class="st0">&quot;System&quot;</span><span class="re2">/&gt;</span></span>
1031
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">namespace</span>=<span class="st0">&quot;System.Collections.Generic&quot;</span><span class="re2">/&gt;</span></span>
1032
+ <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">assembly</span>=<span class="st0">&quot;MyWebApp&quot;</span><span class="re2">/&gt;</span></span>
1033
+ &nbsp;
1034
+ These are null if they're not in the viewdatadictionary or propertybag
1035
+ <span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">warning</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">error</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span>
1036
+ &nbsp;
1037
+ This macro writes out a warning or error if it's in the viewdata.
1038
+ <span class="sc3"><span class="re1">&lt;macro:WarningOrError<span class="re2">&gt;</span></span></span>
1039
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;msgbox warning&quot;</span> <span class="re0">if</span>=<span class="st0">&quot;!string.IsNullOrEmpty(warning)&quot;</span><span class="re2">&gt;</span></span>
1040
+ ${H(warning)}
1041
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
1042
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;msgbox error&quot;</span> <span class="re0">if</span>=<span class="st0">&quot;!string.IsNullOrEmpty(error)&quot;</span><span class="re2">&gt;</span></span>
1043
+ ${H(error)}
1044
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
1045
+ <span class="sc3"><span class="re1">&lt;/macro:WarningOrError<span class="re2">&gt;</span></span></span></pre></div></p>
1046
+
1047
+ <p><b>SomeView.spark</b><br />
1048
+ <div class="geshifilter"><pre class="geshifilter-xml"> <span class="sc3"><span class="re1">&lt;use</span> <span class="re0">import</span>=<span class="st0">&quot;CommonMacros&quot;</span><span class="re2">/&gt;</span></span>
1049
+ ${WarningOrError()}</pre></div></p>
1050
+
1051
+ <p>Import files are much like partial files, except they will not generate rendering code at the points where the &lt;use import=""&gt; occurs. Any text or markup in the imported file, other than the class-level declarations, can be used more or less like comment that won't add a single thing to the generated class or the html output. You can also import the same file from any number of views, partials, and layouts and it's contents will only be used once.</p>
1052
+
1053
+ <p>You may also place a <b>_global.spark</b> in a controller's view folder, or the layouts view folder, and that file will be automatically imported whenever a view or layout template is used from that location. Another file <b>shared\\_global.spark</b> can be created which will be imported once into every single view that's compiled.</p>
1054
+
1055
+ <h3 id="Includingfiles">Including files</h3>
1056
+
1057
+ <p>Another way to manage content is with the &lt;include href=""&gt; element. The implementation of this element is based on a subset of the <a href="http://www.w3.org/TR/xinclude/">xinclude specification</a>. See also O'Reilly <a href="http://www.xml.com/pub/a/2002/07/31/xinclude.html">Using XInclude</a> and MSDN <a href="http://msdn.microsoft.com/en-us/library/aa302291.aspx">Combining XML Documents with XInclude</a>.</p>
1058
+
1059
+ <p>The include and fallback elements are both supported. The include element may have href and parse attributes. The value href must be a relative path, may contain ".." style parent paths, and must include the target file's extension. The dotted parent paths may not go beyond the root of the IViewFolder.</p>
1060
+
1061
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;h2<span class="re2">&gt;</span></span></span>Chapter One<span class="sc3"><span class="re1">&lt;/h2<span class="re2">&gt;</span></span></span>
1062
+ <span class="sc3"><span class="re1">&lt;include</span> <span class="re0">href</span>=<span class="st0">&quot;../lib/chap01.xml&quot;</span><span class="re2">/&gt;</span></span>
1063
+ <span class="sc3"><span class="re1">&lt;hr</span><span class="re2">/&gt;</span></span>
1064
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>Disclaimer<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
1065
+ <span class="sc3"><span class="re1">&lt;include</span> <span class="re0">href</span>=<span class="st0">&quot;../lib/legal.txt&quot;</span> <span class="re0">parse</span>=<span class="st0">&quot;text&quot;</span><span class="re2">&gt;</span></span>
1066
+ <span class="sc3"><span class="re1">&lt;fallback<span class="re2">&gt;</span></span></span>It appears the lawyers have nothing to say.<span class="sc3"><span class="re1">&lt;/fallback<span class="re2">&gt;</span></span></span>
1067
+ <span class="sc3"><span class="re1">&lt;/include<span class="re2">&gt;</span></span></span></pre></div></p>
1068
+
1069
+ <p>You may also use explicit namespaces. Note: declaring namespaces with xmlns attibutes is all-or-nothing. If you declare the XInclude namespace in a file you must also declare the Spark namespace and use element prefixes.</p>
1070
+
1071
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;shimmer&quot;</span> <span class="re0">xmlns:s</span>=<span class="st0">&quot;http://sparkviewengine.com/&quot;</span> <span class="re0">xmlns:xi</span>=<span class="st0">&quot;http://www.w3.org/2001/XInclude&quot;</span><span class="re2">&gt;</span></span>
1072
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Let's add a stylesheet to the header<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1073
+ <span class="sc3"><span class="re1">&lt;s:content</span> <span class="re0">name</span>=<span class="st0">&quot;head&quot;</span><span class="re2">&gt;</span></span>
1074
+ <span class="sc3"><span class="re1">&lt;style</span> <span class="re0">type</span>=<span class="st0">&quot;text/css&quot;</span><span class="re2">&gt;</span></span>
1075
+ <span class="sc3"><span class="re1">&lt;xi:include</span> <span class="re0">href</span>=<span class="st0">&quot;../lib/effects.css&quot;</span> <span class="re0">parse</span>=<span class="st0">&quot;text&quot;</span><span class="re2">/&gt;</span></span>
1076
+ <span class="sc3"><span class="re1">&lt;/style<span class="re2">&gt;</span></span></span>
1077
+ <span class="sc3"><span class="re1">&lt;/s:content<span class="re2">&gt;</span></span></span>
1078
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
1079
+
1080
+ <p>When a file is including another file it happens before <em>any</em> significant processing takes place. As far as the Spark view engine is concerned the contents of the target file may as well have been copy-and-pasted right at the location of the include element. This can have some advantages, but be cautions about duplicate macro declarations or circular include references.</p>
1081
+ </div>
1082
+ <div id="node-43" class="section-2">
1083
+ <h1 class="book-heading">Output Caching</h1>
1084
+ <div class="messages warning">Requires Spark version 1.1</div>
1085
+
1086
+ <div class="toc">
1087
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
1088
+ <div class="toc-list">
1089
+ <ul>
1090
+
1091
+ <ul>
1092
+
1093
+ <ul>
1094
+ <li><a href="#Cachingpartofatemplate">Caching part of a template</a></li>
1095
+ <li><a href="#Cachingthatvariesbyparameters">Caching that varies by parameters</a></li>
1096
+ <li><a href="#Givingcacheaspecifictimetolive">Giving cache a specific time-to-live</a></li>
1097
+ <li><a href="#Expiringwhenunusedovertime">Expiring when unused over time</a></li>
1098
+ <li><a href="#UsingValueHolderforcleanviews">Using ValueHolder for clean views</a></li>
1099
+ <li><a href="#Signalingdependentdatachanged">Signaling dependent data changed</a></li>
1100
+ <li><a href="#Usingcachewithxmlattributes">Using cache with xml attributes</a></li>
1101
+ </ul>
1102
+ </li>
1103
+ </ul>
1104
+ </li>
1105
+ </ul>
1106
+ </div>
1107
+ </div>
1108
+
1109
+ <h3 id="Cachingpartofatemplate">Caching part of a template</h3>
1110
+
1111
+ <p>Output from a Spark template may be cached by wrapping it in a <code>&lt;cache&gt;</code>
1112
+ element. Let's assuming you have a ShowConversionTable macro that does some expensive data acquisition through a service class.</p>
1113
+
1114
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Conversion</span>=<span class="st0">&quot;IConversionRateService&quot;</span><span class="re2">/&gt;</span></span>
1115
+ <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span>A cached section<span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span>
1116
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Current conversion rate ${Conversion.CurrentRate}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1117
+ !{ShowConversionTable(Conversion)}</pre></div></p>
1118
+
1119
+ <p>You could cache the results of this html output by wrapping the section.</p>
1120
+
1121
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">Conversion</span>=<span class="st0">&quot;IConversionRateService&quot;</span><span class="re2">/&gt;</span></span>
1122
+ <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span>A cached section<span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span>
1123
+ <span class="sc3"><span class="re1">&lt;cache<span class="re2">&gt;</span></span></span>
1124
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Current conversion rate ${Conversion.CurrentRate}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1125
+ !{ShowConversionTable(Conversion)}
1126
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1127
+
1128
+ <p>The second and subsequent times this template renders it will reuse the output from the first time it ran. This output would be stored in the ASP.NET cache the first time the cached segment had run.</p>
1129
+
1130
+ <p>Note! It's generally considered a bad practice for the view to acquire the data or model which it is exposing. In further examples below we will see a way to keep data acquisition in your controller's action in a way that caching will still avoid the data acquisition costs.</p>
1131
+
1132
+ <h3 id="Cachingthatvariesbyparameters">Caching that varies by parameters</h3>
1133
+
1134
+ <p>Frequently you'll want to cache things which don't show the same data on every request, or don't appear the same to all users. For example, let's say our conversion table has a parameter to determine the currency to use as the baseline denomination. In that case you would provide the additional key values that would make the output to cache unique.</p>
1135
+
1136
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1137
+ <span class="re0">Conversion</span>=<span class="st0">&quot;IConversionRateService&quot;</span>
1138
+ <span class="re0">Baseline</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span>
1139
+ <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span>A cached section<span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span>
1140
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;Baseline&quot;</span><span class="re2">&gt;</span></span>
1141
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Current rate over Euro ${Conversion.GetCurrentRate(Baseline, &quot;EUR&quot;)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1142
+ !{ShowConversionTable(Conversion, Baseline)}
1143
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1144
+
1145
+ <p>Several parameters may be delimited by commas. This works because attribute value is used as a <code>params object[] keys</code> argument, so if commas are present it create a multiple-field key for the cache entry.</p>
1146
+
1147
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1148
+ <span class="re0">Conversion</span>=<span class="st0">&quot;IConversionRateService&quot;</span>
1149
+ <span class="re0">Baseline</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span>
1150
+ <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span>A cached section<span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span>
1151
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;Baseline, CurrentUserProfile.CountryOfOrigin.Currency&quot;</span><span class="re2">&gt;</span></span>
1152
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">userCurrency</span>=<span class="st0">&quot;CurrentUserProfile.CountryOfOrigin.Currency&quot;</span><span class="re2">/&gt;</span></span>
1153
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${Baseline} rate over ${userCurrency} ${Conversion.GetCurrentRate(Baseline, userCurrency)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1154
+ !{ShowConversionTable(Conversion, Baseline)}
1155
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1156
+
1157
+ <h3 id="Givingcacheaspecifictimetolive">Giving cache a specific time-to-live</h3>
1158
+
1159
+ <p>In the first example the same information could be returned for the life of the web host's app domain. In a lot of cases there's a certain point where you would consider the age of the data to be acceptable. To ensure the same output will only be used for five minutes from when it was originally capured you would provide an expires attribute with a DateTime coordinate, preferable in Utc.</p>
1160
+
1161
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1162
+ <span class="re0">Conversion</span>=<span class="st0">&quot;IConversionRateService&quot;</span>
1163
+ <span class="re0">Baseline</span>=<span class="st0">&quot;string&quot;</span><span class="re2">/&gt;</span></span>
1164
+ <span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span>A cached section<span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span>
1165
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;Baseline&quot;</span> <span class="re0">expires</span>=<span class="st0">&quot;DateTime.UtcNow.AddMinutes(5)&quot;</span><span class="re2">&gt;</span></span>
1166
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Current rate over Euro ${Conversion.GetCurrentRate(Baseline, &quot;EUR&quot;)}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1167
+ !{ShowConversionTable(Conversion, Baseline)}
1168
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1169
+
1170
+ <p>The expires attribute may be used with or without a key. In this example having both present would be correct.</p>
1171
+
1172
+ <h3 id="Expiringwhenunusedovertime">Expiring when unused over time</h3>
1173
+
1174
+ <p>You may have part of a view that isn't particularly time sensitive, but you don't want the entries to remain in memory when their key value hasn't been used for a while. That could be a case to consider using a TimeSpan instead of a DateTime for the expires parameter.</p>
1175
+
1176
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;h1<span class="re2">&gt;</span></span></span>Product Details<span class="sc3"><span class="re1">&lt;/h1<span class="re2">&gt;</span></span></span>
1177
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;productId&quot;</span> <span class="re0">expires</span>=<span class="st0">&quot;TimeSpan.FromMinutes(20)&quot;</span><span class="re2">&gt;</span></span>
1178
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${product.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1179
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;productimage&quot;</span><span class="re2">&gt;</span></span>${ShowProductImage(product.Id)}<span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
1180
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${product.Description}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1181
+ <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">class</span>=<span class="st0">&quot;orderhistory&quot;</span><span class="re2">&gt;</span></span>
1182
+ ${ShowThirtyDayOrderingHistory(product.Id)}
1183
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
1184
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1185
+
1186
+ <p>For convenience a numeric value will be treated as the value of a TimeSpan in seconds.</p>
1187
+
1188
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">expires</span>=<span class="st0">&quot;600&quot;</span><span class="re2">&gt;</span></span>
1189
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>
1190
+ This will remain cached until you stop
1191
+ using the page for ten minutes.
1192
+ <span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1193
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1194
+
1195
+ <p>Note! This example is again implying the view is acquiring data. A preferred method would be to have this information represented by a model added to the ViewData by the controller's action. Next we will look at avoiding that problem.</p>
1196
+
1197
+ <h3 id="UsingValueHolderforcleanviews">Using ValueHolder for clean views</h3>
1198
+
1199
+ <p>As often as possible you will want to ensure the controller's action is gathering all of the model information needed for the view to render itself. This causes a problem when you are attempting to utilize caching, because it's often the gathering of the model's data where the real cost occurs.</p>
1200
+
1201
+ <p>One way to ensure caching will avoid this cost is to have the view gather the data needed for the portion of the template which is cached. That way then a cache-hit occurs you also avoid the cost of making WCF or database calls to acquire the data.</p>
1202
+
1203
+ <p>A better way however would be to take advantage of a class like the <code>ValueHolder</code> provided by the <code>spark.dll</code> assembly. It's a class with a generic typed Value property, and the constructor accepts a lambda expression which will be called at most once the first time the value is used. The lambda may also reference local variables and action arguments even though it's technically being called when the view result is executing.</p>
1204
+
1205
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> ActionResult Details<span class="br0">&#40;</span><span class="kw4">int</span> id<span class="br0">&#41;</span>
1206
+ <span class="br0">&#123;</span>
1207
+ <span class="kw4">var</span> data <span class="sy0">=</span> <span class="kw3">new</span> NorthwindDataContext<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1208
+ &nbsp;
1209
+ ViewData<span class="br0">&#91;</span><span class="st0">&quot;employeeId&quot;</span><span class="br0">&#93;</span> <span class="sy0">=</span> id<span class="sy0">;</span>
1210
+ &nbsp;
1211
+ ViewData<span class="br0">&#91;</span><span class="st0">&quot;employee&quot;</span><span class="br0">&#93;</span> <span class="sy0">=</span> ValueHolder.<span class="kw1">For</span><span class="br0">&#40;</span>
1212
+ <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> data.<span class="me1">Employees</span>.<span class="me1">Single</span><span class="br0">&#40;</span>x <span class="sy0">=&gt;</span> x.<span class="me1">EmployeeID</span> <span class="sy0">==</span> id<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1213
+ &nbsp;
1214
+ <span class="kw1">return</span> View<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1215
+ <span class="br0">&#125;</span></pre></div></p>
1216
+
1217
+ <p>One of the ways you could use this in a view is like this. Because the value property is only used in a cached section, the database not called if the same employee is viewed within three minutes.</p>
1218
+
1219
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1220
+ <span class="re0">employeeId</span>=<span class="st0">&quot;int&quot;</span>
1221
+ <span class="re0">employee</span>=<span class="st0">&quot;Spark.ValueHolder[[Employee]]&quot;</span><span class="re2">/&gt;</span></span>
1222
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;employeeId&quot;</span> <span class="re0">expires</span>=<span class="st0">&quot;180&quot;</span><span class="re2">&gt;</span></span>
1223
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${employee.Value.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1224
+ !{ShowSalesHistory(employee.Value)}
1225
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1226
+
1227
+ <p>There's also an interesting trick with the <code>&lt;viewdata&gt;</code> element you can use if you want to take advantage of Eval's ability to access properties directly. In this case it will add a <code>public Employee employee { get }</code> property which will <code>return (Employee)ViewData.Eval("employee.Value");</code>.</p>
1228
+
1229
+ <p>The net result is that you can use the property <code>employee</code> directly without adding the <code>.Value</code> onto it.</p>
1230
+
1231
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1232
+ <span class="re0">employeeId</span>=<span class="st0">&quot;int&quot;</span>
1233
+ employee.<span class="re0">Value</span>=<span class="st0">&quot;Employee employee&quot;</span><span class="re2">/&gt;</span></span>
1234
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;employeeId&quot;</span> <span class="re0">expires</span>=<span class="st0">&quot;180&quot;</span><span class="re2">&gt;</span></span>
1235
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${employee.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1236
+ !{ShowSalesHistory(employee)}
1237
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1238
+
1239
+ <p>You can also create a <code>ValueHolder</code> with a typed Key property, and use other class methods to acquire the data instead of a lambda expression.</p>
1240
+
1241
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> ActionResult Details<span class="br0">&#40;</span><span class="kw4">int</span> id<span class="br0">&#41;</span>
1242
+ <span class="br0">&#123;</span>
1243
+ ViewData<span class="br0">&#91;</span><span class="st0">&quot;employee&quot;</span><span class="br0">&#93;</span> <span class="sy0">=</span> ValueHolder.<span class="kw1">For</span><span class="sy0">&lt;</span><span class="kw4">int</span>, Employee<span class="sy0">&gt;</span><span class="br0">&#40;</span>id, FetchEmployee<span class="br0">&#41;</span><span class="sy0">;</span>
1244
+ &nbsp;
1245
+ <span class="kw1">return</span> View<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1246
+ <span class="br0">&#125;</span>
1247
+ &nbsp;
1248
+ <span class="kw1">private</span> <span class="kw1">static</span> Employee FetchEmployee<span class="br0">&#40;</span><span class="kw4">int</span> employeeID<span class="br0">&#41;</span>
1249
+ <span class="br0">&#123;</span>
1250
+ <span class="kw4">var</span> data <span class="sy0">=</span> <span class="kw3">new</span> NorthwindDataContext<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1251
+ <span class="kw1">return</span> data.<span class="me1">Employees</span>.<span class="me1">Single</span><span class="br0">&#40;</span>x <span class="sy0">=&gt;</span> x.<span class="me1">EmployeeID</span> <span class="sy0">==</span> employeeID<span class="br0">&#41;</span><span class="sy0">;</span>
1252
+ <span class="br0">&#125;</span></pre></div></p>
1253
+
1254
+ <p>And you can use this key property from the <code>ValueHolder&lt;TKey, TValue&gt;</code> class like this.</p>
1255
+
1256
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">employee</span>=<span class="st0">&quot;Spark.ValueHolder[[int, Employee]]&quot;</span><span class="re2">/&gt;</span></span>
1257
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;employee.Key&quot;</span> <span class="re0">expires</span>=<span class="st0">&quot;180&quot;</span><span class="re2">&gt;</span></span>
1258
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${employee.Value.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1259
+ !{ShowSalesHistory(employee.Value)}
1260
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1261
+
1262
+ <p>Or you could use the Eval trick again like this.</p>
1263
+
1264
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1265
+ employee.<span class="re0">Key</span>=<span class="st0">&quot;int employeeId&quot;</span>
1266
+ employee.<span class="re0">Value</span>=<span class="st0">&quot;Employee employee&quot;</span><span class="re2">/&gt;</span></span>
1267
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;employeeId&quot;</span> <span class="re0">expires</span>=<span class="st0">&quot;180&quot;</span><span class="re2">&gt;</span></span>
1268
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${employee.Name}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1269
+ !{ShowSalesHistory(employee)}
1270
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1271
+
1272
+ <h3 id="Signalingdependentdatachanged">Signaling dependent data changed</h3>
1273
+
1274
+ <p>Expiring the cached output when it reaches a certain age, or when unused for a certain period, always involves a trade-off. With a shorted expiration you're losing cache efficiency, because it's being re-generated more frequently, and with longer expiration you're accepting the fact the web site will return information that's out of date for a certain period. That can be
1275
+ especially noticeable if your web site is on a server farm, because the different nodes may return different cached results if you refresh a page repeatedly.</p>
1276
+
1277
+ <p>To have ultimate control over your cached data you may provide an ICacheSignal that will fire an event when the data changes. Say you have a component that has a <code>RegionSalesBuilder.GetFigures(int regionId)</code> method, and you also implement a <code>RegionSalesWatcher.GetSignalForRegion(int regionId)</code> that will return an ICacheSignal.</p>
1278
+
1279
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> ActionResult SalesFigures<span class="br0">&#40;</span><span class="kw4">int</span> id<span class="br0">&#41;</span>
1280
+ <span class="br0">&#123;</span>
1281
+ <span class="kw4">var</span> worker <span class="sy0">=</span> <span class="kw3">new</span> RegionSalesBuilder<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1282
+ <span class="kw4">var</span> watcher <span class="sy0">=</span> <span class="kw3">new</span> RegionSalesWatcher<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1283
+ <span class="kw1">return</span> View<span class="br0">&#40;</span><span class="kw3">new</span> <span class="br0">&#123;</span>
1284
+ regionId <span class="sy0">=</span> id,
1285
+ figures <span class="sy0">=</span> ValueHolder.<span class="kw1">For</span><span class="sy0">&lt;</span><span class="kw4">int</span>, RegionSales<span class="sy0">&gt;</span><span class="br0">&#40;</span>id, worker.<span class="me1">GetFigures</span><span class="br0">&#41;</span>,
1286
+ salesChanged <span class="sy0">=</span> watcher.<span class="me1">GetSignalForRegion</span><span class="br0">&#40;</span>id<span class="br0">&#41;</span>,
1287
+ <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1288
+ <span class="br0">&#125;</span></pre></div></p>
1289
+
1290
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span>
1291
+ <span class="re0">regionId</span>=<span class="st0">&quot;int&quot;</span>
1292
+ <span class="re0">figures</span>=<span class="st0">&quot;ValueHolder[[RegionSales]]&quot;</span>
1293
+ <span class="re0">salesChanged</span>=<span class="st0">&quot;ICacheSignal&quot;</span><span class="re2">/&gt;</span></span>
1294
+ <span class="sc3"><span class="re1">&lt;cache</span> <span class="re0">key</span>=<span class="st0">&quot;regionId&quot;</span> <span class="re0">signal</span>=<span class="st0">&quot;salesChanged&quot;</span><span class="re2">&gt;</span></span>
1295
+ All of the ${figures.Value.Stuff} shown here
1296
+ <span class="sc3"><span class="re1">&lt;/cache<span class="re2">&gt;</span></span></span></pre></div></p>
1297
+
1298
+ <p>The ICacheSignal contains only a single event named Changed, and you may implement that interface in any way you would like. For example you can use a single instance of that object for your entire database, or you could have a distinct instance for each piece of data you want to expire individually.</p>
1299
+
1300
+ <p>There is also a CacheSignal class you may use which implements ICacheSignal. It has a public method named FireChanged you may call at any time to expire all cached output which used that instance as a signal.</p>
1301
+
1302
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw4">class</span> RegionSalesWatcher
1303
+ <span class="br0">&#123;</span>
1304
+ <span class="kw1">static</span> CacheSignal _allDataSignal <span class="sy0">=</span> <span class="kw3">new</span> CacheSignal<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1305
+ &nbsp;
1306
+ ICacheSignal GetSignalForRegion<span class="br0">&#40;</span><span class="kw4">int</span> regionId<span class="br0">&#41;</span>
1307
+ <span class="br0">&#123;</span>
1308
+ <span class="kw1">return</span> _allDataSignal<span class="sy0">;</span>
1309
+ <span class="br0">&#125;</span>
1310
+ &nbsp;
1311
+ <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">void</span> AppStarted<span class="br0">&#40;</span><span class="br0">&#41;</span>
1312
+ <span class="br0">&#123;</span>
1313
+ <span class="co1">//obvious pseudo-code</span>
1314
+ <span class="kw4">var</span> conn <span class="sy0">=</span> opendatabase<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1315
+ conn.<span class="me1">selecttableswithnotification</span><span class="br0">&#40;</span>OnTablesChanged<span class="br0">&#41;</span><span class="sy0">;</span>
1316
+ <span class="br0">&#125;</span>
1317
+ &nbsp;
1318
+ <span class="kw1">static</span> <span class="kw1">void</span> OnTablesChanged<span class="br0">&#40;</span><span class="br0">&#41;</span>
1319
+ <span class="br0">&#123;</span>
1320
+ _allDataSignal.<span class="me1">FireChanged</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1321
+ <span class="br0">&#125;</span>
1322
+ <span class="br0">&#125;</span></pre></div></p>
1323
+
1324
+ <p>Yet way of using CacheSignal would be as a base class. In this case you would override the Enabled and Disabled methods to build up and tear down the change watching mechanism, and call the base FireChanged when a change occurs.</p>
1325
+
1326
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw4">class</span> FileWatcherSignal <span class="sy0">:</span> ChangeSignal
1327
+ <span class="br0">&#123;</span>
1328
+ <span class="kw4">string</span> _path<span class="sy0">;</span>
1329
+ <span class="kw1">public</span> FileWatcherSignal<span class="br0">&#40;</span><span class="kw4">string</span> path<span class="br0">&#41;</span>
1330
+ <span class="br0">&#123;</span>
1331
+ _path <span class="sy0">=</span> path<span class="sy0">;</span>
1332
+ <span class="br0">&#125;</span>
1333
+ &nbsp;
1334
+ <span class="kw1">protected</span> <span class="kw1">override</span> <span class="kw1">void</span> Enable<span class="br0">&#40;</span><span class="br0">&#41;</span>
1335
+ <span class="br0">&#123;</span>
1336
+ pseudo_code_start_file_watcher<span class="br0">&#40;</span>FileWatcher_ChangedEventHandler<span class="br0">&#41;</span><span class="sy0">;</span>
1337
+ <span class="br0">&#125;</span>
1338
+ &nbsp;
1339
+ <span class="kw1">protected</span> <span class="kw1">override</span> <span class="kw1">void</span> Disable<span class="br0">&#40;</span><span class="br0">&#41;</span>
1340
+ <span class="br0">&#123;</span>
1341
+ pseudo_code_stop_file_watcher<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1342
+ <span class="br0">&#125;</span>
1343
+ &nbsp;
1344
+ <span class="kw1">void</span> FileWatcher_ChangedEventHandler<span class="br0">&#40;</span><span class="br0">&#41;</span>
1345
+ <span class="br0">&#123;</span>
1346
+ FireChanged<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1347
+ <span class="br0">&#125;</span>
1348
+ <span class="br0">&#125;</span></pre></div></p>
1349
+
1350
+ <p>Although Spark provides support for signaling cache expiration, and the ICacheSignal interface and CacheSignal class, there are no built-in implementations of file or database change notifiers. The assumption is that databases and their access libraries are so varied there's a vanishingly small change canned implementations would be useful.</p>
1351
+
1352
+ <p>Or how does this sound... Send me a patch and I'll add them. :)</p>
1353
+
1354
+ <h3 id="Usingcachewithxmlattributes">Using cache with xml attributes</h3>
1355
+
1356
+ <p>The <code>&lt;cache&gt;</code> element can be implied by adding certain attributes to other elements.</p>
1357
+
1358
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div</span> cache.<span class="re0">key</span>=<span class="st0">&quot;employeeId&quot;</span>
1359
+ cache.<span class="re0">expires</span>=<span class="st0">&quot;TimeSpan.FromMinutes(20)&quot;</span>
1360
+ cache.<span class="re0">signal</span>=<span class="st0">&quot;MyApp.Signals.Employees&quot;</span><span class="re2">&gt;</span></span>
1361
+ This div element is cached.
1362
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
1363
+
1364
+ <p>The attribute <code>cache="xxx"</code> is an alias for <code>cache.key="xxx"</code></p>
1365
+
1366
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div</span> <span class="re0">cache</span>=<span class="st0">&quot;employeeId&quot;</span> cache.<span class="re0">expires</span>=<span class="st0">&quot;180&quot;</span><span class="re2">&gt;</span></span>
1367
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>This has a 3 minute sliding expiration per employee id<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1368
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>${employeeId}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1369
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span></pre></div></p>
1370
+ </div>
1371
+ <div id="node-11" class="section-2">
1372
+ <h1 class="book-heading">Precompiling Views</h1>
1373
+ <p><div class="toc">
1374
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
1375
+ <div class="toc-list">
1376
+ <ul>
1377
+
1378
+ <ul>
1379
+
1380
+ <ul>
1381
+ <li><a href="#PrecompilingonstartupwiththeAspNetMvcSparkViewFactory">Precompiling on-startup with the Asp.Net Mvc SparkViewFactory</a></li>
1382
+ <li><a href="#PrecompilingonstartupwiththeCastleMonoRailSparkViewFactory">Precompiling on-startup with the Castle MonoRail SparkViewFactory</a></li>
1383
+ <li><a href="#PrecompilingonstartupwiththelowlevelSparkViewEngine">Precompiling on-startup with the low-level SparkViewEngine</a></li>
1384
+ <li><a href="#Usingprecompilationinaunittest">Using precompilation in a unit test</a></li>
1385
+ <li><a href="#Precompilingbindeployableassemblywithinstallutilandwithapostbuildstep">Precompiling bin-deployable assembly with installutil and with a post-build step</a></li>
1386
+ <li><a href="#Loadingadeployedprecompiledassembly">Loading a deployed precompiled assembly</a></li>
1387
+ <li><a href="#Configuringbatchdescriptors">Configuring batch descriptors</a></li>
1388
+ </ul>
1389
+ </li>
1390
+ </ul>
1391
+ </li>
1392
+ </ul>
1393
+ </div>
1394
+ </div></p>
1395
+
1396
+ <p>You can create a precompiled assembly with view classes at a high level with the a batch descriptor and a SparkViewFactory, or at a low level with an array of view descriptors and a SparkViewEngine.</p>
1397
+
1398
+ <p>If you provide a high-level batch descriptor to the asp.net mvc or castle monorail SparkViewFactory it will be converted into an array of descriptors based on which view files exist. Those will then be passed to the SparkViewEngine.</p>
1399
+
1400
+ <h3 id="PrecompilingonstartupwiththeAspNetMvcSparkViewFactory">Precompiling on-startup with the Asp.Net Mvc SparkViewFactory</h3>
1401
+
1402
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"> <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">void</span> PrecompileViews<span class="br0">&#40;</span>ControllerBuilder builder<span class="br0">&#41;</span>
1403
+ <span class="br0">&#123;</span>
1404
+ <span class="kw4">var</span> controllerFactory <span class="sy0">=</span> <span class="br0">&#40;</span>SparkControllerFactory<span class="br0">&#41;</span>builder.<span class="me1">GetControllerFactory</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1405
+ <span class="kw4">var</span> viewFactory <span class="sy0">=</span> <span class="kw3">new</span> SparkViewFactory<span class="br0">&#40;</span>controllerFactory.<span class="me1">Settings</span><span class="br0">&#41;</span><span class="sy0">;</span>
1406
+ <span class="kw4">var</span> batch <span class="sy0">=</span> <span class="kw3">new</span> SparkBatchDescriptor<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1407
+ batch
1408
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>HomeController<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
1409
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>ProductsController<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1410
+ viewFactory.<span class="me1">Precompile</span><span class="br0">&#40;</span>batch<span class="br0">&#41;</span><span class="sy0">;</span>
1411
+ <span class="br0">&#125;</span></pre></div></p>
1412
+
1413
+ <p>A static method like this would be called from Global Application_Start. The tricky part is getting your hands on the instance of the view factory.</p>
1414
+
1415
+ <h3 id="PrecompilingonstartupwiththeCastleMonoRailSparkViewFactory">Precompiling on-startup with the Castle MonoRail SparkViewFactory</h3>
1416
+
1417
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//todo - about the same. just need sample code</span></pre></div></p>
1418
+
1419
+ <h3 id="PrecompilingonstartupwiththelowlevelSparkViewEngine">Precompiling on-startup with the low-level SparkViewEngine</h3>
1420
+
1421
+ <p>If you create an instance of the SparkViewEngine you can call BatchCompilation directly. It takes the name of the target assembly, which should have the .dll extension, and a list of SparkViewDescriptor which have been filled in. The SparkViewEngine will need to have the ViewFolder property set.</p>
1422
+
1423
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"> <span class="kw4">var</span> engine <span class="sy0">=</span> <span class="kw3">new</span> SparkViewEngine<span class="br0">&#40;</span>settings<span class="br0">&#41;</span>
1424
+ <span class="br0">&#123;</span>
1425
+ ViewFolder <span class="sy0">=</span> <span class="kw3">new</span> FileSystemViewFolder<span class="br0">&#40;</span>viewsLocation<span class="br0">&#41;</span>
1426
+ <span class="br0">&#125;</span><span class="sy0">;</span>
1427
+ &nbsp;
1428
+ engine.<span class="me1">BatchCompilation</span><span class="br0">&#40;</span>targetPath, Global.<span class="me1">AllKnownDescriptors</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
1429
+
1430
+ <h3 id="Usingprecompilationinaunittest">Using precompilation in a unit test</h3>
1431
+
1432
+ <p>With Asp.Net Mvc the view factory is fairly easy to create when you need it. The tricky part can be making sure the path to the views folder is correct. You could pass in settings or assume that the spark section in the app.config in your test project is correct.</p>
1433
+
1434
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"> <span class="kw4">var</span> viewFactory <span class="sy0">=</span> <span class="kw3">new</span> SparkViewFactory<span class="br0">&#40;</span>settings<span class="br0">&#41;</span>
1435
+ <span class="br0">&#123;</span>
1436
+ ViewSourceLoader <span class="sy0">=</span> <span class="kw3">new</span> FileSystemViewSourceLoader<span class="br0">&#40;</span><span class="st0">@&quot;..\..\..\NorthwindDemo\Views&quot;</span><span class="br0">&#41;</span>
1437
+ <span class="br0">&#125;</span><span class="sy0">;</span>
1438
+ &nbsp;
1439
+ <span class="kw4">var</span> batch <span class="sy0">=</span> <span class="kw3">new</span> SparkBatchDescriptor<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1440
+ batch.<span class="kw1">For</span><span class="sy0">&lt;</span>ProductsController<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1441
+ viewFactory.<span class="me1">Precompile</span><span class="br0">&#40;</span>batch<span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
1442
+
1443
+ <p>The return value of Precompile and BatchCompilation is the resulting loaded Assembly. You could continue to make assertions about the number of types in the file.</p>
1444
+
1445
+ <h3 id="Precompilingbindeployableassemblywithinstallutilandwithapostbuildstep">Precompiling bin-deployable assembly with installutil and with a post-build step</h3>
1446
+
1447
+ <p>This one is probably the coolest one. Especially if you're developing a web app to deploy to a medium trust shared environment. You can find some examples of this in the Samples\AspNetMvc\PrecompiledViews project and Samples\DirectUsage\MediumTrustHosting project.</p>
1448
+
1449
+ <p>First: Add the following to the web.config. This will cause an exception to be thrown if your web app ever tries to compile a view at runtime, which will help avoid a situation where you work in development (because the view will generate on the fly) but not in production.</p>
1450
+
1451
+ <p><div class="geshifilter"><pre class="geshifilter-xml"> <span class="sc3"><span class="re1">&lt;system</span>.web<span class="re2">&gt;</span></span>
1452
+ <span class="sc3"><span class="re1">&lt;trust</span> <span class="re0">level</span>=<span class="st0">&quot;Medium&quot;</span> <span class="re2">/&gt;</span></span>
1453
+ ...</pre></div></p>
1454
+
1455
+ <p>Second: Add a new Installer Class item to your web project. It will have a grey designer surface. From the toolbox drag a new instance of either the MvcContrib.SparkViewEngine.Install.PrecompileInstaller or the Castle.MonoRail.Views.Spark.Install.PrecompileInstaller onto this surface. </p>
1456
+
1457
+ <p>(If it's not in the toolbox you may need to right-click one of the categories, say "Choose Items...", and Browse... to locate the assembly that contains the tool you want.)</p>
1458
+
1459
+ <p>Third: Select the precompileInstaller1 you just added. If you like you can provide a target assembly file name - by default it will add .Views.dll to your web app assembly name. Then choose the events in the properties (yellow lightning) and double-click "DescribeBatch". Provide the implementation, for example:</p>
1460
+
1461
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"> <span class="kw1">private</span> <span class="kw1">void</span> precompileInstaller1_DescribeBatch<span class="br0">&#40;</span><span class="kw4">object</span> sender, DescribeBatchEventArgs e<span class="br0">&#41;</span>
1462
+ <span class="br0">&#123;</span>
1463
+ e.<span class="me1">Batch</span>
1464
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>HomeController<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
1465
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>HomeController<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">Layout</span><span class="br0">&#40;</span><span class="st0">&quot;Ajax&quot;</span><span class="br0">&#41;</span>.<span class="me1">Include</span><span class="br0">&#40;</span><span class="st0">&quot;_Notification&quot;</span><span class="br0">&#41;</span>
1466
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>AccountController<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1467
+ <span class="br0">&#125;</span></pre></div></p>
1468
+
1469
+ <p>You could also add a static to Global and have this event handler call that static if you don't want to bury information like this in an event on a designer of an installer component. You could also then re-use that function from a unit test that compiles everything also.</p>
1470
+
1471
+ <p>Fourth and finally: Right-click the web project, choose properties, and change the Build Events. Add the following Post-build event command line:</p>
1472
+
1473
+ <p><div class="geshifilter"><pre class="geshifilter-xml">%systemroot%\Microsoft.NET\Framework\v2.0.50727\installutil &quot;$(TargetPath)&quot;</pre></div></p>
1474
+
1475
+ <p>Done! Now every time you hit Build, or F5-Debug/Run, or run unit tests from visual studio you'll automatically generate the precompiled views assembly in the bin directory. Plus, as icing on the cake, if there are any errors that occur in the installer they'll show up in the build output.</p>
1476
+
1477
+ <p><div class="geshifilter"><pre class="geshifilter-xml">------ Build started: Project: PrecompiledViews, Configuration: Debug Any CPU ------
1478
+ PrecompiledViews -&gt; E:\Projects\spark\src\Samples\AspNetMvc\PrecompiledViews\bin\PrecompiledViews.dll
1479
+ %systemroot%\Microsoft.NET\Framework\v2.0.50727\installutil &quot;E:\Projects\spark\src\Samples\AspNetMvc\PrecompiledViews\bin\PrecompiledViews.dll&quot;
1480
+ Microsoft (R) .NET Framework Installation utility Version 2.0.50727.1433
1481
+ Copyright (c) Microsoft Corporation. All rights reserved.
1482
+ ...etc...
1483
+ An exception occurred during the Install phase.
1484
+ Spark.Compiler.CompilerException: Dynamic view compilation failed.
1485
+ generated.cs(20,22): error CS0103: The name 'hi' does not exist in the current context</pre></div></p>
1486
+
1487
+ <h3 id="Loadingadeployedprecompiledassembly">Loading a deployed precompiled assembly</h3>
1488
+
1489
+ <p>When the app loads, usually in Global.Application_Start, you can load an existing precompiled view assembly instead of generating one. You would need to call SparkViewEngine's LoadCompilation(Assembly precompiled) method. It will enumerate all of the public types in the assembly to recreate and cache the appropriate SparkViewDescriptors. The array of descriptors which were loaded are returned.</p>
1490
+
1491
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"> <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">void</span> LoadPrecompiledViews<span class="br0">&#40;</span>SparkViewFactory factory<span class="br0">&#41;</span>
1492
+ <span class="br0">&#123;</span>
1493
+ factory.<span class="me1">Engine</span>.<span class="me1">LoadBatchCompilation</span><span class="br0">&#40;</span>Assembly.<span class="me1">Load</span><span class="br0">&#40;</span><span class="st0">&quot;MyWebApp.Views.dll&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1494
+ <span class="br0">&#125;</span></pre></div></p>
1495
+
1496
+ <p>As always, the tricky part can be getting your hands on an instance of the SparkViewFactory.</p>
1497
+
1498
+ <p>There is no dynamic recompilation of classes that are loaded in this way and changes to the spark files will have no effect. However the files must be available on disk at runtime. Sorry about that - but the different frameworks still needs to test for the view files' existence to know what view descriptor it should instantiate.</p>
1499
+
1500
+ <h3 id="Configuringbatchdescriptors">Configuring batch descriptors</h3>
1501
+
1502
+ <p>The batch descriptor contains multiple entries and is built with a fluent interface. The target assembly name can be provided on the constructor, otherwise the assembly will be named after a guid and go to the temporary asp.net files directory.</p>
1503
+
1504
+ <p>Each call to .For&lt;YourController&gt;() starts a new rule entry. Within a rule you can call Layout, Include, and Exclude multiple times. Include and Exclude can have patterns that end with *. If the pattern ends with * it won't find things in "Shared". The other special case is the single character "*" which matches anything that doesn't start with an underscore. </p>
1505
+
1506
+ <p><div class="geshifilter"><pre class="geshifilter-csharp">batch
1507
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>HomeController<span class="sy0">&gt;</span>
1508
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>HomeController<span class="sy0">&gt;</span>.<span class="me1">Layout</span><span class="br0">&#40;</span><span class="st0">&quot;ajax&quot;</span><span class="br0">&#41;</span>.<span class="me1">Include</span><span class="br0">&#40;</span><span class="st0">&quot;_*&quot;</span><span class="br0">&#41;</span>
1509
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>ProductsController<span class="sy0">&gt;</span>.<span class="me1">Include</span><span class="br0">&#40;</span><span class="st0">&quot;Index&quot;</span><span class="br0">&#41;</span>.<span class="me1">Include</span><span class="br0">&#40;</span><span class="st0">&quot;List&quot;</span><span class="br0">&#41;</span>.<span class="me1">Include</span><span class="br0">&#40;</span><span class="st0">&quot;Detail&quot;</span><span class="br0">&#41;</span>
1510
+ .<span class="kw1">For</span><span class="sy0">&lt;</span>AccountController<span class="sy0">&gt;</span>.<span class="me1">Include</span><span class="br0">&#40;</span><span class="st0">&quot;*&quot;</span><span class="br0">&#41;</span>.<span class="me1">Exclude</span><span class="br0">&#40;</span><span class="st0">&quot;TestMessage&quot;</span><span class="br0">&#41;</span>.<span class="me1">Exclude</span><span class="br0">&#40;</span><span class="st0">&quot;Blah&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
1511
+
1512
+ <p>If Include is not called for a rule the default is to include all views that don't start with a "_". If Layout is not called the default is to use the layout that would be used automatically appropriate for the framework in question. If you call .Layout multiple times it'll generate a class for each combination of layout and view. That's if you want to precompile several themes where the controller will specify the layout at runtime.</p>
1513
+
1514
+ <p>A call to layout can take an array of strings. This is <em>not</em> the same as calling Layout multiple times - rather it's to support MonoRail's ability to organize the layout into several layers.</p>
1515
+ </div>
1516
+ <div id="node-14" class="section-2">
1517
+ <h1 class="book-heading">View Locations</h1>
1518
+ <div class="toc">
1519
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
1520
+ <div class="toc-list">
1521
+ <ul>
1522
+
1523
+ <ul>
1524
+ <li><a href="#Sparkfilepatterns">Spark file patterns</a></li>
1525
+ <li><a href="#Extendingfilepatternswithdescriptorfilters">Extending file patterns with descriptor filters</a>
1526
+ <ul>
1527
+ <li><a href="#AreaDescriptorFilter">AreaDescriptorFilter</a></li>
1528
+ <li><a href="#ThemeDescriptorFilter">ThemeDescriptorFilter</a></li>
1529
+ <li><a href="#LanguageDescriptorFilter">LanguageDescriptorFilter</a></li>
1530
+ </ul>
1531
+ </li>
1532
+ <li><a href="#CustomIDescriptorFilterimplementations">Custom IDescriptorFilter implementations</a></li>
1533
+ <li><a href="#UnderstandingIViewFolderandIViewFile">Understanding IViewFolder and IViewFile</a></li>
1534
+ <li><a href="#Defaultviewfolderlocations">Default view folder locations</a></li>
1535
+ <li><a href="#Addingaviewfoldertoconfig">Adding a view folder to config</a></li>
1536
+ <li><a href="#Understandingthesubfolderparameter">Understanding the subfolder parameter</a></li>
1537
+ </ul>
1538
+ </li>
1539
+ </ul>
1540
+ </div>
1541
+ </div>
1542
+
1543
+ <h2 id="Sparkfilepatterns">Spark file patterns</h2>
1544
+
1545
+ <p>Spark will locate files using a very conventional pattern. These patterns will not change no matter which view folders are configured.</p>
1546
+
1547
+ <p>For controller views, the name of the controller and the name of the view are combined, like <code>home\index.spark</code>. If that file does not exist the name of the view is looked for in the Shared folder, like <code>shared\index.spark</code>.</p>
1548
+
1549
+ <p>For master layout templates, the name of the master will looked for in the Layouts folder, like <code>layouts\application.spark</code>. If that file does not exist it too will be looked for in the Shared folder, like <code>shared\application.spark</code>.</p>
1550
+
1551
+ <p>These patters will be looked for <em>inside</em> the view folder implementations. The view folders will never alter that part of the Spark file pattern, and the patterns won't affect the location of the view folders. This is very different from the behavior of the WebForms view engine which allows you to provide an array of customized virtual paths.</p>
1552
+
1553
+ <p>Sorry, but it was simply impossible to give the view engine full control of the entire path and remain compatible with the different frameworks and existing usage. The customized virtual paths are also incompatible with some of the specialized view folder sources.</p>
1554
+
1555
+ <h2 id="Extendingfilepatternswithdescriptorfilters">Extending file patterns with descriptor filters</h2>
1556
+
1557
+ <p>This is an ASP.NET MVC specific feature. In MonoRail the framework locates the view files and the paths are provided explicitly.</p>
1558
+
1559
+ <p>The SparkViewFactory uses a IDescriptorBuilder service to turn master, controller, and view names into a SparkViewDescriptor. The DefaultDescriptorBuilder provides a mechanism to add any number of IDescriptorFilter implementations to modify the potential locations of a view using information from the current request context.</p>
1560
+
1561
+ <p>There are three build-in implementations of IDescriptorFilter: AreaDescriptorFilter, LanguageDescriptorFilter, and ThemeDescriptorFilter. All three are optional, but the AreaDescriptorFilter is added by default. The other two require the web application to provide the mechanism that identifies a theme or language for a request.</p>
1562
+
1563
+ <p>Note: this descriptor filters only alter the search paths for views, layouts, and asp.net partial views. It does not change the search paths for <code>_filename.spark</code> partial files.</p>
1564
+
1565
+ <p>Here is example of adding a language filter. The LanguageDecriptorFilter is an abstract class, so you either need to inherit and implement or use the static method For which takes a lambda expression or method reference.</p>
1566
+
1567
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">void</span> RegisterViewEngine<span class="br0">&#40;</span>ICollection<span class="sy0">&lt;</span>IViewEngine<span class="sy0">&gt;</span> engines<span class="br0">&#41;</span>
1568
+ <span class="br0">&#123;</span>
1569
+ <span class="kw4">var</span> services <span class="sy0">=</span> SparkEngineStarter.<span class="me1">CreateContainer</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1570
+ services.<span class="me1">AddFilter</span><span class="br0">&#40;</span>LanguageDescriptorFilter.<span class="kw1">For</span><span class="br0">&#40;</span>GetSessionCulture<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1571
+ SparkEngineStarter.<span class="me1">RegisterViewEngine</span><span class="br0">&#40;</span>services<span class="br0">&#41;</span><span class="sy0">;</span>
1572
+ <span class="br0">&#125;</span>
1573
+ <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">string</span> GetSessionCulture<span class="br0">&#40;</span>ControllerContext controllerContext<span class="br0">&#41;</span>
1574
+ <span class="br0">&#123;</span>
1575
+ <span class="kw1">return</span> Convert.<span class="me1">ToString</span><span class="br0">&#40;</span>controllerContext.<span class="me1">HttpContext</span>.<span class="me1">Session</span><span class="br0">&#91;</span><span class="st0">&quot;culture&quot;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1576
+ <span class="br0">&#125;</span></pre></div></p>
1577
+
1578
+ <h3 id="AreaDescriptorFilter">AreaDescriptorFilter</h3>
1579
+
1580
+ <p>The area filter by default detects an {area} RouteData.Value. It is added as leading folder.</p>
1581
+
1582
+ <p>For example, with Area:Sales, Controller:Foo, and View:Bar the locations:</p>
1583
+
1584
+ <ul>
1585
+ <li>Foo/Bar.spark</li>
1586
+ <li>Shared/Bar.spark</li>
1587
+ </ul>
1588
+
1589
+ <p>become:</p>
1590
+
1591
+ <ul>
1592
+ <li>Sales/Foo/Bar.spark</li>
1593
+ <li>Sales/Shared/Bar.spark</li>
1594
+ <li>Foo/Bar.spark</li>
1595
+ <li>Shared/Bar.spark</li>
1596
+ </ul>
1597
+
1598
+ <h3 id="ThemeDescriptorFilter">ThemeDescriptorFilter</h3>
1599
+
1600
+ <p>The theme filter requires a lambda expression or method reference at a minimum (see above). The theme could be stored anywhere in the request context like a session variable, cookie, or user profile settings.</p>
1601
+
1602
+ <p>The filter will extend the potential locations for views by prefixing a Themes folder and the name of the theme to the potential locations. For example, with Theme:CleanBlue, Controller:Foo, and View:Bar the potential locations:</p>
1603
+
1604
+ <ul>
1605
+ <li>Foo/Bar.spark</li>
1606
+ <li>Shared/Bar.spark</li>
1607
+ </ul>
1608
+
1609
+ <p>become:</p>
1610
+
1611
+ <ul>
1612
+ <li>Themes/CleanBlue/Foo/Bar.spark</li>
1613
+ <li>Themes/CleanBlue/Sales/Shared/Bar.spark</li>
1614
+ <li>Foo/Bar.spark</li>
1615
+ <li>Shared/Bar.spark</li>
1616
+ </ul>
1617
+
1618
+ <h3 id="LanguageDescriptorFilter">LanguageDescriptorFilter</h3>
1619
+
1620
+ <p>Like the theme filter, the language descriptor filter requires a lambda expression when it's registered.</p>
1621
+
1622
+ <p>This filter operates by inserting the language-locale, and just the language, before the extension on each potential location. For example, with Langauge:en-US, Controller:Foo, and View:Bar the potential locations:</p>
1623
+
1624
+ <ul>
1625
+ <li>Foo/Bar.spark</li>
1626
+ <li>Shared/Bar.spark</li>
1627
+ </ul>
1628
+
1629
+ <p>become:</p>
1630
+
1631
+ <ul>
1632
+ <li>Foo/Bar.en-US.spark</li>
1633
+ <li>Foo/Bar.en.spark</li>
1634
+ <li>Foo/Bar.spark</li>
1635
+ <li>Shared/Bar.en-US.spark</li>
1636
+ <li>Shared/Bar.en.spark</li>
1637
+ <li>Shared/Bar.spark</li>
1638
+ </ul>
1639
+
1640
+ <h2 id="CustomIDescriptorFilterimplementations">Custom IDescriptorFilter implementations</h2>
1641
+
1642
+ <p>It should be very simple to implement a custom descriptor filter. The only two methods are <code>ExtraParameters</code>, which is called frequently to extract significant values for the filter from the current context, and <code>PotentialLocations</code>, which is called on a cache-miss to extend the list of paths where a given view template may exist.</p>
1643
+
1644
+ <p>As an example, this is the implementation of the AreaDescriptorFilter.</p>
1645
+
1646
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw4">class</span> AreaDescriptorFilter <span class="sy0">:</span> DescriptorFilterBase
1647
+ <span class="br0">&#123;</span>
1648
+ <span class="kw1">public</span> <span class="kw1">override</span> <span class="kw1">void</span> ExtraParameters<span class="br0">&#40;</span>
1649
+ ControllerContext context,
1650
+ IDictionary<span class="sy0">&lt;</span><span class="kw4">string</span>, <span class="kw4">object</span><span class="sy0">&gt;</span> extra<span class="br0">&#41;</span>
1651
+ <span class="br0">&#123;</span>
1652
+ <span class="kw4">object</span> value<span class="sy0">;</span>
1653
+ <span class="kw1">if</span> <span class="br0">&#40;</span>context.<span class="me1">RouteData</span>.<span class="me1">Values</span>.<span class="me1">TryGetValue</span><span class="br0">&#40;</span><span class="st0">&quot;area&quot;</span>, <span class="kw1">out</span> value<span class="br0">&#41;</span><span class="br0">&#41;</span>
1654
+ extra<span class="br0">&#91;</span><span class="st0">&quot;area&quot;</span><span class="br0">&#93;</span> <span class="sy0">=</span> value<span class="sy0">;</span>
1655
+ <span class="br0">&#125;</span>
1656
+ &nbsp;
1657
+ <span class="kw1">public</span> <span class="kw1">override</span> IEnumerable<span class="sy0">&lt;</span><span class="kw4">string</span><span class="sy0">&gt;</span> PotentialLocations<span class="br0">&#40;</span>
1658
+ IEnumerable<span class="sy0">&lt;</span><span class="kw4">string</span><span class="sy0">&gt;</span> locations,
1659
+ IDictionary<span class="sy0">&lt;</span><span class="kw4">string</span>, <span class="kw4">object</span><span class="sy0">&gt;</span> extra<span class="br0">&#41;</span>
1660
+ <span class="br0">&#123;</span>
1661
+ <span class="kw4">string</span> areaName<span class="sy0">;</span>
1662
+ <span class="kw1">return</span> TryGetString<span class="br0">&#40;</span>extra, <span class="st0">&quot;area&quot;</span>, <span class="kw1">out</span> areaName<span class="br0">&#41;</span>
1663
+ <span class="sy0">?</span> locations.<span class="me1">Select</span><span class="br0">&#40;</span>x <span class="sy0">=&gt;</span> Path.<span class="me1">Combine</span><span class="br0">&#40;</span>areaName, x<span class="br0">&#41;</span><span class="br0">&#41;</span>.<span class="me1">Concat</span><span class="br0">&#40;</span>locations<span class="br0">&#41;</span>
1664
+ <span class="sy0">:</span> locations<span class="sy0">;</span>
1665
+ <span class="br0">&#125;</span>
1666
+ <span class="br0">&#125;</span></pre></div></p>
1667
+
1668
+ <h2 id="UnderstandingIViewFolderandIViewFile">Understanding IViewFolder and IViewFile</h2>
1669
+
1670
+ <p>The Spark library declares two interfaces which provide the ability to locate view files and load their contents. There are very few methods and several implementations of typical view locations are provided, so in most cases the most you will need to do is provide additional configuration.</p>
1671
+
1672
+ <h2 id="Defaultviewfolderlocations">Default view folder locations</h2>
1673
+
1674
+ <p>In a Castle MonoRail application the configured IViewSourceLoader is used by the default IViewFolder implementation. The root location of the default IViewSourceLoader is <code>~/Views</code> and can be changed with the <code>monorail/viewEngines/@viewPathRoot</code> configuration attribute.</p>
1675
+
1676
+ <p>In an Asp.Net MVC applications a view folder based on hosting environment's VirtualPathProvider is used. The root location within this will be <code>~/Views</code>.</p>
1677
+
1678
+ <p>The behavior of those abstractions can be controlled in ways that aren't documented here; custom VirtualPathProviders is a large topic all on it's own. Whatever you do to the framework to alter how files are loaded should work with Spark as expected.</p>
1679
+
1680
+ <p>What is documented on this page is how to bring in additional IViewFolder implementations to extend the way spark files can be located.</p>
1681
+
1682
+ <h2 id="Addingaviewfoldertoconfig">Adding a view folder to config</h2>
1683
+
1684
+ <p>The <code>&lt;spark&gt;</code> config section accepts a <code>&lt;views&gt;</code> element which can be used to add additional view folder locations.</p>
1685
+
1686
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;spark<span class="re2">&gt;</span></span></span>
1687
+ <span class="sc3"><span class="re1">&lt;views<span class="re2">&gt;</span></span></span>
1688
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">name</span>=<span class="st0">&quot;{any-unique-name}&quot;</span>
1689
+ <span class="re0">folderType</span>=<span class="st0">&quot;FileSystem|EmbeddedResource|VirtualPathProvider|Custom&quot;</span>
1690
+ <span class="re0">type</span>=<span class="st0">&quot;{name, assembly of IViewFolder type}&quot;</span>
1691
+ <span class="re0">constuctor-param-names</span>=<span class="st0">&quot;values&quot;</span>
1692
+ <span class="re0">subfolder</span>=<span class="st0">&quot;{optional subfolder to target}&quot;</span><span class="re2">/&gt;</span></span>
1693
+ <span class="sc3"><span class="re1">&lt;/views<span class="re2">&gt;</span></span></span>
1694
+ <span class="sc3"><span class="re1">&lt;/spark<span class="re2">&gt;</span></span></span></pre></div></p>
1695
+
1696
+ <p>For example:
1697
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;spark<span class="re2">&gt;</span></span></span>
1698
+ <span class="sc3"><span class="re1">&lt;views<span class="re2">&gt;</span></span></span>
1699
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">name</span>=<span class="st0">&quot;stuff&quot;</span> <span class="re0">folderType</span>=<span class="st0">&quot;EmbeddedResource&quot;</span> <span class="re0">assembly</span>=<span class="st0">&quot;MyExtraStuff&quot;</span> <span class="re0">resourcePath</span>=<span class="st0">&quot;MyExtraStuff.Views&quot;</span><span class="re2">/&gt;</span></span>
1700
+ <span class="sc3"><span class="re1">&lt;/views<span class="re2">&gt;</span></span></span>
1701
+ <span class="sc3"><span class="re1">&lt;/spark<span class="re2">&gt;</span></span></span></pre></div></p>
1702
+
1703
+ <h2 id="Understandingthesubfolderparameter">Understanding the subfolder parameter</h2>
1704
+
1705
+ <p>The subfolder parameter will make the contents for a view folder appear at a specific location in the logical views directory. In other words you're adding files, but you're adding them at a subdirectory.</p>
1706
+
1707
+ <p>For example if you create a <code>~/Masters</code> directory in your web app you could expose it in place with the following:
1708
+ <div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;spark<span class="re2">&gt;</span></span></span>
1709
+ <span class="sc3"><span class="re1">&lt;views<span class="re2">&gt;</span></span></span>
1710
+ <span class="sc3"><span class="re1">&lt;add</span> <span class="re0">name</span>=<span class="st0">&quot;morestuff&quot;</span> <span class="re0">folderType</span>=<span class="st0">&quot;VirtualPathProvider&quot;</span> <span class="re0">subfolder</span>=<span class="st0">&quot;layouts&quot;</span> <span class="re0">virtualBaseDir</span>=<span class="st0">&quot;~/Masters&quot;</span><span class="re2">/&gt;</span></span>
1711
+ <span class="sc3"><span class="re1">&lt;/views<span class="re2">&gt;</span></span></span>
1712
+ <span class="sc3"><span class="re1">&lt;/spark<span class="re2">&gt;</span></span></span></pre></div></p>
1713
+
1714
+ <p>Any path can be the target for adding additional files. If no subfolder is provided the contents are added at the root.</p>
1715
+ </div>
1716
+ <div id="node-41" class="section-2">
1717
+ <h1 class="book-heading">Visual Basic</h1>
1718
+ <div class="toc">
1719
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
1720
+ <div class="toc-list">
1721
+ <ul>
1722
+
1723
+ <ul>
1724
+
1725
+ <ul>
1726
+ <li><a href="#Creatinganewproject">Creating a new project</a></li>
1727
+ <li><a href="#Addingviews">Adding views</a></li>
1728
+ </ul>
1729
+ </li>
1730
+ </ul>
1731
+ </li>
1732
+ </ul>
1733
+ </div>
1734
+ </div>
1735
+
1736
+ <h3 id="Creatinganewproject">Creating a new project</h3>
1737
+
1738
+ <p>Assuming you have a Visual Basic ASP.NET MVC web application there are very few things you need to enable Spark. In the end it's very similar to the CSharp implementation.</p>
1739
+
1740
+ <p>First, add references to the following assemblies:</p>
1741
+
1742
+ <ul>
1743
+ <li>Spark.dll</li>
1744
+ <li>Spark.Web.Mvc.dll</li>
1745
+ </ul>
1746
+
1747
+ <p>Then add the following minimal configuration to change Spark's default target language to Visual Basic:</p>
1748
+
1749
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;configuration<span class="re2">&gt;</span></span></span>
1750
+ <span class="sc3"><span class="re1">&lt;configSections<span class="re2">&gt;</span></span></span>
1751
+ ...
1752
+ <span class="sc3"><span class="re1">&lt;section</span> <span class="re0">name</span>=<span class="st0">&quot;spark&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;Spark.Configuration.SparkSectionHandler, Spark&quot;</span><span class="re2">/&gt;</span></span>
1753
+ <span class="sc3"><span class="re1">&lt;/configSections<span class="re2">&gt;</span></span></span>
1754
+ <span class="sc3"><span class="re1">&lt;spark<span class="re2">&gt;</span></span></span>
1755
+ <span class="sc3"><span class="re1">&lt;compilation</span> <span class="re0">defaultLanguage</span>=<span class="st0">&quot;VisualBasic&quot;</span><span class="re2">/&gt;</span></span>
1756
+ <span class="sc3"><span class="re1">&lt;/spark<span class="re2">&gt;</span></span></span>
1757
+ ...
1758
+ <span class="sc3"><span class="re1">&lt;/configuration<span class="re2">&gt;</span></span></span></pre></div></p>
1759
+
1760
+ <p>You'll also want to ensure the <code>&lt;system.codedom&gt;</code> configuration contains a definition of visualbasic which targets the v3.5 framework or higher.</p>
1761
+
1762
+ <p>Finally add the following to your Global.asax file:</p>
1763
+
1764
+ <p><div class="geshifilter"><pre class="geshifilter-xml"> Shared Sub RegisterViewEngines(ByVal engines As ViewEngineCollection)
1765
+ SparkEngineStarter.RegisterViewEngine(engines)
1766
+ End Sub
1767
+ &nbsp;
1768
+ Sub Application_Start()
1769
+ ....
1770
+ RegisterViewEngines(ViewEngines.Engines)
1771
+ End Sub</pre></div></p>
1772
+
1773
+ <h3 id="Addingviews">Adding views</h3>
1774
+
1775
+ <p>At this point everything about Spark works exactly as it does normally with the exception that the CLR syntax used is Visual Basic. Another place to check out VB syntax in Spark is located at <span class="geshifilter"><code class="geshifilter-xml">Samples\AspNetMvc\VisualBasicViews</code></span>.</p>
1776
+
1777
+ <p><div class="geshifilter"><pre class="geshifilter-xml">#' this is a comment
1778
+ &nbsp;
1779
+ <span class="sc3"><span class="coMULTI">&lt;!-- Dim x = 4 + 5 --&gt;</span></span>
1780
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">x</span>=<span class="st0">&quot;4 + 5&quot;</span><span class="re2">/&gt;</span></span>
1781
+ &nbsp;
1782
+ <span class="sc3"><span class="coMULTI">&lt;!-- Dim xx As Invoice = Nothing --&gt;</span></span>
1783
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">xx</span>=<span class="st0">&quot;Nothing&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;Invoice&quot;</span> <span class="re2">/&gt;</span></span>
1784
+ &nbsp;
1785
+ <span class="sc3"><span class="coMULTI">&lt;!-- Note: single = used instead of == --&gt;</span></span>
1786
+ <span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">&quot;x = 9&quot;</span><span class="re2">&gt;</span></span>
1787
+ &nbsp;
1788
+ <span class="sc3"><span class="coMULTI">&lt;!-- Note: VisualBasic does not require 'var' in foreach loop
1789
+ &lt;!-- For Each prod in Products --&gt;</span></span>
1790
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;prod in Products&quot;</span><span class="re2">&gt;</span></span>
1791
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span>
1792
+ &nbsp;
1793
+ <span class="sc3"><span class="coMULTI">&lt;!-- and you can provide type in the loop with optional 'As' --&gt;</span></span>
1794
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;p As Product in Products&quot;</span><span class="re2">&gt;</span></span>
1795
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span>
1796
+ &nbsp;
1797
+ <span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span>
1798
+ &nbsp;
1799
+ <span class="sc3"><span class="coMULTI">&lt;!-- And the rest is about like you'd expect --&gt;</span></span>
1800
+ #Using Html.BeginForm()
1801
+ &nbsp;
1802
+ <span class="sc3"><span class="coMULTI">&lt;!-- although the anonymous object syntax is a bit odd --&gt;</span></span>
1803
+ &nbsp;
1804
+ !{Html.ActionLink(&quot;Show Order&quot;, &quot;View&quot;, New With {.id = MyOrderId} ) }
1805
+ &nbsp;
1806
+ #End Using</pre></div></p>
1807
+ </div>
1808
+ <div id="node-15" class="section-2">
1809
+ <h1 class="book-heading">Iron Python</h1>
1810
+ <div class="toc">
1811
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
1812
+ <div class="toc-list">
1813
+ <ul>
1814
+
1815
+ <ul>
1816
+
1817
+ <ul>
1818
+ <li><a href="#AboutIronPython">About Iron Python</a></li>
1819
+ <li><a href="#Creatinganewproject">Creating a new project</a></li>
1820
+ <li><a href="#Addingviews">Adding views</a></li>
1821
+ <li><a href="#Variable">Variable</a></li>
1822
+ <li><a href="#ViewData">ViewData</a></li>
1823
+ <li><a href="#Loopingandconditional">Looping and conditional</a></li>
1824
+ <li><a href="#Inlinecode">Inline code</a></li>
1825
+ <li><a href="#Invokingmethodsandhelpers">Invoking methods and helpers</a></li>
1826
+ </ul>
1827
+ </li>
1828
+ </ul>
1829
+ </li>
1830
+ </ul>
1831
+ </div>
1832
+ </div>
1833
+
1834
+ <h3 id="AboutIronPython">About Iron Python</h3>
1835
+
1836
+ <p><a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython">Iron Python</a> is a dynamic language runtime (DLR) based implementation of Python. Spark scripting is based on assemblies in the <a href="http://www.codeplex.com/IronPython/Release/ProjectReleases.aspx?ReleaseId=17404">2.0 Release Candidate 1</a> binary zip. Other good resources are the <a href="http://docs.python.org/">Python documentation</a> and the <a href="http://www.python.org/">Python site</a> itself.</p>
1837
+
1838
+ <p>The support for the DLR is very Asp.Net MVC centric. If there's an interest in expanded Castle MonoRail support, <a href="http://groups.google.com/group/spark-dev">please speak up in the discussion group</a>.</p>
1839
+
1840
+ <h3 id="Creatinganewproject">Creating a new project</h3>
1841
+
1842
+ <p>A standard Asp.Net MVC web application is always a great starting place. First, add references to the following assemblies:</p>
1843
+
1844
+ <ul>
1845
+ <li>Spark.dll</li>
1846
+ <li>Spark.Python.dll</li>
1847
+ <li>Spark.Web.Mvc.dll</li>
1848
+ <li>Spark.Web.Mvc.Python.dll</li>
1849
+ </ul>
1850
+
1851
+ <p>And the following from the IronPython release which are available in the Spark bin\dependencies folder. If you have problems with the these files from Codeplex try the ones in from the Spark distribution. You have the "works on my machine" guarantee.</p>
1852
+
1853
+ <ul>
1854
+ <li>Microsoft.Scripting.dll</li>
1855
+ <li>Microsoft.Scripting.Core.dll</li>
1856
+ <li>Microsoft.Scripting.ExtensionAttribute.dll</li>
1857
+ <li>IronPython.dll</li>
1858
+ <li>IronPython.Modules.dll</li>
1859
+ </ul>
1860
+
1861
+ <p>Yeah, I know. It's a lot of assemblies. You're going to love the next part though, adding the Spark view engine to an Asp.Net MVC web application has been simplified.</p>
1862
+
1863
+ <p>Add the following to your Global Application_Start method:</p>
1864
+
1865
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">using</span> <span class="co3">Spark.Web.Mvc.Scripting</span><span class="sy0">;</span>
1866
+ ...
1867
+ <span class="kw1">protected</span> <span class="kw1">void</span> Application_Start<span class="br0">&#40;</span><span class="kw4">object</span> sender, EventArgs e<span class="br0">&#41;</span>
1868
+ <span class="br0">&#123;</span>
1869
+ SparkPythonEngineStarter.<span class="me1">RegisterViewEngine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1870
+ <span class="br0">&#125;</span></pre></div></p>
1871
+
1872
+ <p>This will create a view engine and add it to the engines collection.</p>
1873
+
1874
+ <p>The Spark engine starter also has several utility methods for more advanced initialization. You can, for example, provide a settings object from code. You can also use the ISparkServicesContainer to provide specific implementations of different services used by the Spark engine. For example:</p>
1875
+
1876
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">// this example avoids adding &lt;spark&gt; to web.config</span>
1877
+ <span class="kw4">var</span> settings <span class="sy0">=</span> <span class="kw3">new</span> SparkSettings<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1878
+ &nbsp;
1879
+ <span class="co1">// change settings, like</span>
1880
+ settings
1881
+ .<span class="me1">SetDebug</span><span class="br0">&#40;</span><span class="kw1">true</span><span class="br0">&#41;</span>
1882
+ .<span class="me1">SetPageBaseType</span><span class="br0">&#40;</span><span class="kw3">typeof</span><span class="br0">&#40;</span>MyBasePage<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1883
+ &nbsp;
1884
+ <span class="kw4">var</span> container <span class="sy0">=</span> SparkPythonEngineStarter.<span class="me1">CreateContainer</span><span class="br0">&#40;</span>settings<span class="br0">&#41;</span><span class="sy0">;</span>
1885
+ &nbsp;
1886
+ <span class="co1">// change services, like</span>
1887
+ container.<span class="me1">SetServiceBuilder</span><span class="sy0">&lt;</span>IViewActivatorFactory<span class="sy0">&gt;</span><span class="br0">&#40;</span>
1888
+ c <span class="sy0">=&gt;</span> <span class="kw3">new</span> MyViewActivatorFactory<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1889
+ &nbsp;
1890
+ SparkPythonEngineStarter.<span class="me1">RegisterViewEngine</span><span class="br0">&#40;</span>
1891
+ ViewEngines.<span class="me1">Engines</span>, container<span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
1892
+
1893
+ <h3 id="Addingviews">Adding views</h3>
1894
+
1895
+ <p>Spark views for IronPython look and act much like they would for csharp. They have a .spark extension and exist in the normal <code>Views\&lt;controllername&gt;\&lt;viewname&gt;.spark</code> path.</p>
1896
+
1897
+ <p>One of the most obvious differences would be the lack of a need to declare <code>&lt;viewdata/&gt;</code>. Other than that it's pretty darn straightforward. You can execute code inline with <code>#statement</code> and output information with <code>${expression}</code> and all of the <code>&lt;content&gt;</code>, <code>&lt;macro&gt;</code>, support for underscored partials, imports, etc. is unchanged.</p>
1898
+
1899
+ <p><div class="geshifilter"><pre class="geshifilter-xml">#import clr
1900
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Methods available from the clr module<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1901
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
1902
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;x in dir(clr)&quot;</span><span class="re2">&gt;</span></span>${x}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1903
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span>
1904
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Methods (and extension methods) available to the normal helpers<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1905
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
1906
+ <span class="sc3"><span class="re1">&lt;var</span> <span class="re0">underscores</span>=<span class="st0">&quot;'__'&quot;</span><span class="re2">/&gt;</span></span>
1907
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;x in dir(Html)&quot;</span> <span class="re0">if</span>=<span class="st0">&quot;not x.startswith(underscores)&quot;</span><span class="re2">&gt;</span></span>Html.${x}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1908
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;x in dir(Ajax)&quot;</span> <span class="re0">if</span>=<span class="st0">&quot;not x.startswith(underscores)&quot;</span><span class="re2">&gt;</span></span>Ajax.${x}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1909
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;x in dir(Url)&quot;</span> <span class="re0">if</span>=<span class="st0">&quot;not x.startswith(underscores)&quot;</span><span class="re2">&gt;</span></span>Url.${x}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1910
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
1911
+
1912
+ <p>So once you get past the subtle expression differences it's pretty straightforward. I relied very heavily on the Python language documentation figuring out the syntax to use. If you're comfortable with Python, or simply hate declaring your view data and mucking around with strong types and assembly references, using the DLR might be an attractive option.</p>
1913
+
1914
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
1915
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
1916
+ <span class="sc3"><span class="re1">&lt;global</span> <span class="re0">Title</span>=<span class="st0">&quot;'Python View Language Sample'&quot;</span><span class="re2">/&gt;</span></span>
1917
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${Title}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span>
1918
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
1919
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
1920
+ <span class="sc3"><span class="re1">&lt;use:view</span><span class="re2">/&gt;</span></span>
1921
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
1922
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
1923
+
1924
+ <p><div class="geshifilter"><pre class="geshifilter-xml">#Title = &quot;Products - &quot; + Title
1925
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>There are ${len(products)} products available<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
1926
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
1927
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;p in products&quot;</span><span class="re2">&gt;</span></span>${Html.ActionLink(p.Name, &quot;Show&quot;)}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1928
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
1929
+
1930
+ <h3 id="Variable">Variable</h3>
1931
+
1932
+ <p>Variable scope in Python is very different than in csharp because of the nature of the language itself. The entire view, and the entire master, are both single functions. All of the variables in those two functions are available to all of the views and partial files.</p>
1933
+
1934
+ <p>To share variables between view and master, use the global element, like <code>&lt;global title="'Default Title'"/&gt;</code>. Of course <code>&lt;content name="foo"&gt;...&lt;/content&gt;</code> and <code>&lt;use content="foo"/&gt;</code> can also be used to produce and consume material.</p>
1935
+
1936
+ <p>Other forms of variable declaration all end up meaning the same thing. <code>&lt;var x="5" hello="'world'"/&gt;</code>, <code>&lt;def x="5" hello="'world'"/&gt;</code>, and <code>&lt;set x="5" hello="'world'"/&gt;</code> are virtually interchangable - just remember to assign a variable before you use it.</p>
1937
+
1938
+ <p>Providing a fall-back value with <code>&lt;default x="1" hello="'(your name here)'"/&gt;</code> will work and is very convenient for assigning default values for optional arguments in partials.</p>
1939
+
1940
+ <h3 id="ViewData">ViewData</h3>
1941
+
1942
+ <p>Viewdata does need to be declared because the contents of the dictionary will appear to be global symbols. Because they have a lower precedence than view class members you may need to use <code>ViewData["name"]</code> syntax to access information that collides with existing members.</p>
1943
+
1944
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> ActionResult Index<span class="br0">&#40;</span><span class="br0">&#41;</span>
1945
+ <span class="br0">&#123;</span>
1946
+ ViewData<span class="br0">&#91;</span><span class="st0">&quot;foo&quot;</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;bar&quot;</span><span class="sy0">;</span>
1947
+ <span class="kw1">return</span> View<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
1948
+ <span class="br0">&#125;</span></pre></div></p>
1949
+
1950
+ <p><div class="geshifilter"><pre class="geshifilter-xml">## no declaration needed
1951
+ <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Foo is ${foo}<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span></pre></div></p>
1952
+
1953
+ <h3 id="Loopingandconditional">Looping and conditional</h3>
1954
+
1955
+ <p>Iteration in Python doesn't require a type declaration on the looping variable. Otherwise it's very similar to Spark with csharp.</p>
1956
+
1957
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;c in categories&quot;</span><span class="re2">&gt;</span></span>
1958
+ <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>${H(c.Name)}<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
1959
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
1960
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;p in c.Products&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;alt?{pIndex%2}&quot;</span><span class="re2">&gt;</span></span>${H(p.Name)}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1961
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span>
1962
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></pre></div></p>
1963
+
1964
+ <p>The conditional elements and attributes (test, if, elseif, else) in all their various forms work fine structurally once you take into account language differences. Python will use <code>not</code>, <code>or</code>, and <code>and</code> boolean keywords rather than punctuation operators. It will also infer the value of True for non-default values. So 0, False, and None (or null) all act as false. Which is why the condition <code>?{pIndex%2}</code> above will give you even-odd striping by removing the alt css class as the result of 0 and 1 varies.</p>
1965
+
1966
+ <h3 id="Inlinecode">Inline code</h3>
1967
+
1968
+ <p>The <code>#statement&lt;newline&gt;</code> format works <em>especially</em> well for adding Python code inline, but bear in mind how significant whitespace will be. The statement following the # character will be written at the correct indentation for the place it appears in scope, but there should only be whitespace between the # and the code if you're intentionally creating something scoped to a previous statement.</p>
1969
+
1970
+ <p>One use for that would be declaring a function.</p>
1971
+
1972
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>Declaring a function<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
1973
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
1974
+ #import math
1975
+ ## Calculate the n-dimensional hypotenuse
1976
+ #def vectorlength(vector):
1977
+ # dt = 0
1978
+ # for d in vector:
1979
+ # dt = dt + d * d
1980
+ # return math.sqrt(dt)
1981
+ <span class="sc3"><span class="re1">&lt;li<span class="re2">&gt;</span></span></span>3,4 : ${vectorlength([3,4])}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1982
+ <span class="sc3"><span class="re1">&lt;li<span class="re2">&gt;</span></span></span>12,13 : ${vectorlength([12,13])}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1983
+ <span class="sc3"><span class="re1">&lt;li<span class="re2">&gt;</span></span></span>0,5,3,2,0,6 : ${vectorlength([0,5,3,2,0,6])}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
1984
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
1985
+
1986
+ <p>Note, since # is a comment in python ## can be used in Spark as a code-comment which won't appear in html output.</p>
1987
+
1988
+ <h3 id="Invokingmethodsandhelpers">Invoking methods and helpers</h3>
1989
+
1990
+ <p>All methods and properties of the base view class are available . If you're writing output explicitly there is a subtle problem with overloaded methods, like Output.Write(...), when the DLR determines which method to invoke. Writing a number for example will throw an exception because the several flavors of integer and floating point are ambiguous from the scripting point of view. Another method OutputWriteAdapter(object value) has been added to the scripting-specific spark view class, and that is the method ${expression} will invoke.</p>
1991
+
1992
+ <p>Some helper methods can be particularly tricky. It appears that native IronPython property-bearing reflect with put properties Keys and Values, so they can't be used for helper methods which take an anonymous type as a dictionary. The good news is you can typically call a different overload of the helper method by building the CLR dictionary classes.</p>
1993
+
1994
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
1995
+ #import clr
1996
+ #clr.AddReference(&quot;System.Web.Routing&quot;)
1997
+ #from System.Web.Routing import RouteValueDictionary
1998
+ #routeData = RouteValueDictionary()
1999
+ &nbsp;
2000
+ #routeData[&quot;id&quot;] = page.CurrentPage - 1
2001
+ <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;${Url.Action(action, controller, routeData)}&quot;</span><span class="re2">&gt;</span></span><span class="sc1">&amp;laquo;</span> Previous<span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
2002
+ &nbsp;
2003
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;pageIndex in range(1, page.PageCount + 1)&quot;</span><span class="re2">&gt;</span></span>
2004
+ #routeData[&quot;id&quot;] = pageIndex
2005
+ <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;${Url.Action(action, controller, routeData)}&quot;</span><span class="re2">&gt;</span></span>${pageIndex}<span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
2006
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span>
2007
+ &nbsp;
2008
+ #routeData[&quot;id&quot;] = page.CurrentPage + 1
2009
+ <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;${Url.Action(action, controller, routeData)}&quot;</span><span class="re2">&gt;</span></span>Next <span class="sc1">&amp;raquo;</span><span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
2010
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
2011
+ &nbsp;</pre></div></p>
2012
+ </div>
2013
+ <div id="node-16" class="section-2">
2014
+ <h1 class="book-heading">Iron Ruby</h1>
2015
+ <div class="toc">
2016
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
2017
+ <div class="toc-list">
2018
+ <ul>
2019
+
2020
+ <ul>
2021
+
2022
+ <ul>
2023
+ <li><a href="#AboutIronRuby">About Iron Ruby</a></li>
2024
+ <li><a href="#Creatinganewproject">Creating a new project</a></li>
2025
+ <li><a href="#Addingviews">Adding views</a></li>
2026
+ <li><a href="#Invokingmethodsandhelpers">Invoking methods and helpers</a></li>
2027
+ </ul>
2028
+ </li>
2029
+ </ul>
2030
+ </li>
2031
+ </ul>
2032
+ </div>
2033
+ </div>
2034
+
2035
+ <h3 id="AboutIronRuby">About Iron Ruby</h3>
2036
+
2037
+ <p><a href="http://www.ironruby.net/">Iron Ruby</a> is a <a href="http://blogs.msdn.com/hugunin/archive/2007/04/30/a-dynamic-language-runtime-dlr.aspx">dynamic language runtime</a> (DLR) based implementation of <a href="http://www.ruby-lang.org/en/">Ruby</a>. Spark's Ruby integration is based on slightly modified <a href="http://rubyforge.org/scm/?group_id=4359">trunk code</a>. Other good resources are <a href="http://www.ruby-lang.org/en/documentation/">Ruby documentation</a> and <a href="http://www.ruby-doc.org/docs/ProgrammingRuby/">Programming Ruby</a>.</p>
2038
+
2039
+ <p>The build of IronRuby used for Spark has had the assemblies <code>Microsoft.Scripting.*</code> assemblies renamed <code>NonStandard.Microsoft.Scripting.*</code>. Those libraries appear to be works in progess and some irreconcilable differences existed in these shared assemblies in the IronPython and IronRuby sources which were available at the time the integration with Spark was done. As those projects evolve the need for two sets of assemblies should disappear.</p>
2040
+
2041
+ <p>The support for the DLR is very Asp.Net MVC centric. If there's an interest in expanded Castle MonoRail support, <a href="http://groups.google.com/group/spark-dev">please speak up in the discussion group</a>.</p>
2042
+
2043
+ <h3 id="Creatinganewproject">Creating a new project</h3>
2044
+
2045
+ <p>A standard Asp.Net MVC web application is always a great starting place. First, add references to the following assemblies:</p>
2046
+
2047
+ <ul>
2048
+ <li>Spark.dll</li>
2049
+ <li>Spark.Ruby.dll</li>
2050
+ <li>Spark.Web.Mvc.dll</li>
2051
+ <li>Spark.Web.Mvc.Ruby.dll</li>
2052
+ </ul>
2053
+
2054
+ <p>And the following from the IronRuby release which are available in the Spark bin\dependencies folder. If you have problems with the these files from RubyForge try the ones in from the Spark distribution. You have the "works on my machine" guarantee.</p>
2055
+
2056
+ <ul>
2057
+ <li>NonStandard.Microsoft.Scripting.dll</li>
2058
+ <li>NonStandard.Microsoft.Scripting.Core.dll</li>
2059
+ <li>NonStandard.Microsoft.Scripting.ExtensionAttribute.dll</li>
2060
+ <li>IronRuby.dll</li>
2061
+ <li>IronRuby.Library.dll</li>
2062
+ </ul>
2063
+
2064
+ <p>Yeah, I know. It's a lot of assemblies. You're going to love the next part though, adding the Spark view engine to an Asp.Net MVC web application has been simplified.</p>
2065
+
2066
+ <p>Add the following to your Global Application_Start method:</p>
2067
+
2068
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">using</span> <span class="co3">Spark.Web.Mvc.Ruby</span><span class="sy0">;</span>
2069
+ ...
2070
+ <span class="kw1">protected</span> <span class="kw1">void</span> Application_Start<span class="br0">&#40;</span><span class="kw4">object</span> sender, EventArgs e<span class="br0">&#41;</span>
2071
+ <span class="br0">&#123;</span>
2072
+ SparkRubyEngineStarter.<span class="me1">RegisterViewEngine</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
2073
+ <span class="br0">&#125;</span></pre></div></p>
2074
+
2075
+ <p>This will create a view engine and add it to the engines collection.</p>
2076
+
2077
+ <p>The Spark engine starter also has several utility methods for more advanced initialization. You can, for example, provide a settings object from code. You can also use the ISparkServicesContainer to provide specific implementations of different services used by the Spark engine. For example:</p>
2078
+
2079
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">// this example avoids adding &lt;spark&gt; to web.config</span>
2080
+ <span class="kw4">var</span> settings <span class="sy0">=</span> <span class="kw3">new</span> SparkSettings<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
2081
+ &nbsp;
2082
+ <span class="co1">// change settings, like</span>
2083
+ settings
2084
+ .<span class="me1">SetDebug</span><span class="br0">&#40;</span><span class="kw1">true</span><span class="br0">&#41;</span>
2085
+ .<span class="me1">SetPageBaseType</span><span class="br0">&#40;</span><span class="kw3">typeof</span><span class="br0">&#40;</span>MyBasePage<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
2086
+ &nbsp;
2087
+ <span class="kw4">var</span> container <span class="sy0">=</span> SparkRubyEngineStarter.<span class="me1">CreateContainer</span><span class="br0">&#40;</span>settings<span class="br0">&#41;</span><span class="sy0">;</span>
2088
+ &nbsp;
2089
+ <span class="co1">// change services, like</span>
2090
+ container.<span class="me1">SetServiceBuilder</span><span class="sy0">&lt;</span>IViewActivatorFactory<span class="sy0">&gt;</span><span class="br0">&#40;</span>
2091
+ c <span class="sy0">=&gt;</span> <span class="kw3">new</span> MyViewActivatorFactory<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
2092
+ &nbsp;
2093
+ SparkRubyEngineStarter.<span class="me1">RegisterViewEngine</span><span class="br0">&#40;</span>
2094
+ ViewEngines.<span class="me1">Engines</span>, container<span class="br0">&#41;</span><span class="sy0">;</span></pre></div></p>
2095
+
2096
+ <h3 id="Addingviews">Adding views</h3>
2097
+
2098
+ <p>Spark views for IronRuby look and act much like they would for csharp. They have a .spark extension and exist in the normal <code>Views\&lt;controllername&gt;\&lt;viewname&gt;.spark</code> path.</p>
2099
+
2100
+ <p>The syntax of Ruby on Spark is a bit rhtml-like. Spark supports <code>&lt;%= ... %&gt;</code> and <code>&lt;% ...%&gt;</code> in the same way, and the dictionary of ViewData values are added as <code>@name</code> attributes. Of course, just like other Spark variations can also execute code inline with <code>#statement</code> and output information with <code>${expression}</code> and all of the <code>&lt;content&gt;</code>, <code>&lt;macro&gt;</code>, support for underscored partials, imports, etc. is unchanged.</p>
2101
+
2102
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;html<span class="re2">&gt;</span></span></span>
2103
+ <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
2104
+ <span class="sc3"><span class="re1">&lt;global</span> <span class="re0">title</span>=<span class="st0">&quot;'Python View Language Sample'&quot;</span><span class="re2">/&gt;</span></span>
2105
+ <span class="sc3"><span class="re1">&lt;title<span class="re2">&gt;</span></span></span>${@title}<span class="sc3"><span class="re1">&lt;/title<span class="re2">&gt;</span></span></span>
2106
+ <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
2107
+ <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
2108
+ <span class="sc3"><span class="re1">&lt;use:view</span><span class="re2">/&gt;</span></span>
2109
+ <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
2110
+ <span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></p>
2111
+
2112
+ <p><div class="geshifilter"><pre class="geshifilter-xml">#@title = &quot;Products - &quot; + @title
2113
+ <span class="sc3"><span class="re1">&lt;ul<span class="re2">&gt;</span></span></span>
2114
+ <span class="sc3"><span class="re1">&lt;li</span> <span class="re0">each</span>=<span class="st0">&quot;p in @products&quot;</span><span class="re2">&gt;</span></span>${html.ActionLink(p.name, &quot;Show&quot;)}<span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
2115
+ <span class="sc3"><span class="re1">&lt;/ul<span class="re2">&gt;</span></span></span></pre></div></p>
2116
+
2117
+ <h3 id="Invokingmethodsandhelpers">Invoking methods and helpers</h3>
2118
+
2119
+ <p>All methods and properties of the base view class are available. Ruby naming convention may be in effect, so if a symbol like ViewData isn't resolved try using view_data.</p>
2120
+
2121
+ <p>Some helper methods can be particularly tricky. It appears that native IronRuby can't be used for helper methods which take an anonymous type as a dictionary. The good news is you can typically call those helper methods with a CLR dictionary class you can create. The following is a bit of simplified code from the samples\AspNetMvc\IronRubyViews project available in the download.</p>
2122
+
2123
+ <p><div class="geshifilter"><pre class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;div<span class="re2">&gt;</span></span></span>
2124
+ ## make a clr route dictionary for url.action
2125
+ #require 'System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
2126
+ #routeData = System::Web::Routing::RouteValueDictionary.new
2127
+ &nbsp;
2128
+ ## monkey patch an id setter equivalent to {routeData[&quot;id&quot;] = value}
2129
+ #def routeData.id=(value); set_Item('id',value); end
2130
+ &nbsp;
2131
+ #routeData.id = page.CurrentPage - 1
2132
+ <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;${url.action(action, controller, routeData)}&quot;</span><span class="re2">&gt;</span></span><span class="sc1">&amp;laquo;</span> Previous<span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
2133
+ &nbsp;
2134
+ <span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;pageIndex in 1..page.PageCount&quot;</span><span class="re2">&gt;</span></span>
2135
+ #routeData.id = pageIndex
2136
+ <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;${url.action(action, controller, routeData)}&quot;</span><span class="re2">&gt;</span></span>${pageIndex}<span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
2137
+ <span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span>
2138
+ &nbsp;
2139
+ #routeData.id = page.CurrentPage + 1
2140
+ <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;${url.action(action, controller, routeData)}&quot;</span><span class="re2">&gt;</span></span>Next <span class="sc1">&amp;raquo;</span><span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
2141
+ <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
2142
+ &nbsp;</pre></div></p>
2143
+ </div>
2144
+ <div id="node-37" class="section-2">
2145
+ <h1 class="book-heading">Reference</h1>
2146
+ <h2 id="SparkReference">Spark Reference</h2>
2147
+
2148
+ <p>Template elements, attributes, and configuration reference information</p>
2149
+ <div id="node-38" class="section-3">
2150
+ <h1 class="book-heading">Elements</h1>
2151
+ <div class="toc">
2152
+ <div class="toc-title">Table of Contents [<a href="#" class="toc-toggle">hide</a>]</div>
2153
+ <div class="toc-list">
2154
+ <ul>
2155
+
2156
+ <ul>
2157
+ <li><a href="#content">content</a>
2158
+ <ul>
2159
+ <li><a href="#withname">with name=""</a></li>
2160
+ <li><a href="#withvarordef">with var="" or def=""</a></li>
2161
+ <li><a href="#withset">with set=""</a></li>
2162
+ </ul>
2163
+ </li>
2164
+ <li><a href="#def">def</a></li>
2165
+ <li><a href="#default">default</a>
2166
+ <ul>
2167
+ <li><a href="#withtype">with type=""</a></li>
2168
+ </ul>
2169
+ </li>
2170
+ <li><a href="#else">else</a>
2171
+ <ul>
2172
+ <li><a href="#withif">with if=""</a></li>
2173
+ <li><a href="#emptyelement">empty element</a></li>
2174
+ </ul>
2175
+ </li>
2176
+ <li><a href="#elseif">elseif</a></li>
2177
+ <li><a href="#for">for</a>
2178
+ <ul>
2179
+ <li><a href="#withassignments">with *="" assignments</a></li>
2180
+ </ul>
2181
+ </li>
2182
+ <li><a href="#global">global</a>
2183
+ <ul>
2184
+ <li><a href="#withtype-1">with type=""</a></li>
2185
+ </ul>
2186
+ </li>
2187
+ <li><a href="#if">if</a></li>
2188
+ <li><a href="#include">include</a></li>
2189
+ <li><a href="#macro">macro</a></li>
2190
+ <li><a href="#render">render</a>
2191
+ <ul>
2192
+ <li><a href="#withsection">with section=""</a></li>
2193
+ <li><a href="#withassignments-1">with *="" assignments</a></li>
2194
+ <li><a href="#withfallbackcontent">with fallback content</a></li>
2195
+ </ul>
2196
+ </li>
2197
+ <li><a href="#renderpartial">render partial=""</a>
2198
+ <ul>
2199
+ <li><a href="#withassignments-2">with *="" assignments</a></li>
2200
+ </ul>
2201
+ </li>
2202
+ <li><a href="#section">section</a>
2203
+ <ul>
2204
+ <li><a href="#withassignments-3">with *="" assignments</a></li>
2205
+ </ul>
2206
+ </li>
2207
+ <li><a href="#set">set</a></li>
2208
+ <li><a href="#test">test</a></li>
2209
+ <li><a href="#useassembly">use assembly=""</a></li>
2210
+ <li><a href="#usecontent">use content=""</a>
2211
+ <ul>
2212
+ <li><a href="#withfallbackcontent-1">with fallback content</a></li>
2213
+ </ul>
2214
+ </li>
2215
+ <li><a href="#usefile">use file=""</a></li>
2216
+ <li><a href="#useimport">use import=""</a></li>
2217
+ <li><a href="#usemaster">use master=""</a></li>
2218
+ <li><a href="#usenamespace">use namespace=""</a></li>
2219
+ <li><a href="#var">var</a>
2220
+ <ul>
2221
+ <li><a href="#withtype-2">with type=""</a></li>
2222
+ </ul>
2223
+ </li>
2224
+ <li><a href="#viewdata">viewdata</a>
2225
+ <ul>
2226
+ <li><a href="#withdefault">with default=""</a></li>
2227
+ <li><a href="#withpropertyname">with property name</a></li>
2228
+ </ul>
2229
+ </li>
2230
+ <li><a href="#viewdatamodel">viewdata model=""</a>
2231
+ <ul>
2232
+ <li><a href="#withpropertyname-1">with property name</a></li>
2233
+ </ul>
2234
+ </li>
2235
+ <li><a href="#Seealsosourcecode">See also: source code</a></li>
2236
+ </ul>
2237
+ </li>
2238
+ </ul>
2239
+ </div>
2240
+ </div>
2241
+
2242
+ <hr />
2243
+
2244
+ <h2 id="content">content</h2>
2245
+
2246
+ <p>Captures output contained within the content element to a text spool or local variable.</p>
2247
+
2248
+ <h3 id="withname">with name=""</h3>
2249
+
2250
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">name</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span></code></span></p>
2251
+
2252
+ <p>Spools all output in the content element into a named text writer. The named content can be placed as output later with a <code>&lt;use/&gt;</code> element, or can be accessed directly with the <code>Content["x"]</code> dictionary.</p>
2253
+
2254
+ <h3 id="withvarordef">with var="" or def=""</h3>
2255
+
2256
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">var</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span></code></span></p>
2257
+
2258
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">def</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span></code></span></p>
2259
+
2260
+ <p>Spools all output into a temporary text writer, then assigns the results into a new string local variable named by the var attribute value.</p>
2261
+
2262
+ <h3 id="withset">with set=""</h3>
2263
+
2264
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">set</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span></code></span></p>
2265
+
2266
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;content</span> <span class="re0">set</span>=<span class="st0">&quot;x&quot;</span> <span class="re0">add</span>=<span class="st0">&quot;before|after|replace&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/content<span class="re2">&gt;</span></span></span></code></span></p>
2267
+
2268
+ <p>Spools all output into a temporary text writer, then assigns the results into an existing local variable named by the set attribute value.</p>
2269
+
2270
+ <p>If the content element also contains <code>add="after"</code> the capured content will be appended to the end of the variable's existing value. If it contains <code>add="before"</code> the content will be appended to the front of the existing variable value.</p>
2271
+
2272
+ <hr />
2273
+
2274
+ <h2 id="def">def</h2>
2275
+
2276
+ <p>An alias for declaring a local variable, see <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span><span class="re2">/&gt;</span></span></code></span>.</p>
2277
+
2278
+ <hr />
2279
+
2280
+ <h2 id="default">default</h2>
2281
+
2282
+ <p>Declares local variables if a symbol of a given name is not known to be in scope.</p>
2283
+
2284
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;default</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2285
+
2286
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2287
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span></pre></div></p>
2288
+
2289
+ <p>If a symbol x or y is known to exist in scope as a local variable, or declared viewdata or global property, the line declaring the variable will not be generated.</p>
2290
+
2291
+ <h3 id="withtype">with type=""</h3>
2292
+
2293
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;default</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;t&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2294
+
2295
+ <p><div class="geshifilter"><pre class="geshifilter-csharp">t x <span class="sy0">=</span> a<span class="sy0">;</span>
2296
+ t y <span class="sy0">=</span> b<span class="sy0">;</span></pre></div></p>
2297
+
2298
+ <hr />
2299
+
2300
+ <h2 id="else">else</h2>
2301
+
2302
+ <p>Forms a part of an if/elseif/else conditional structure.</p>
2303
+
2304
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;else<span class="re2">&gt;</span></span></span>anyXml<span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span></code></span></p>
2305
+
2306
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">else</span>
2307
+ <span class="br0">&#123;</span>
2308
+ <span class="co1">//anyXml-generated-code</span>
2309
+ <span class="br0">&#125;</span></pre></div></p>
2310
+
2311
+ <p>Must follow an element that produces an if/elseif statement. Contains material that will be rendered if all preceding conditions are false.</p>
2312
+
2313
+ <h3 id="withif">with if=""</h3>
2314
+
2315
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span></code></span></p>
2316
+
2317
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">else</span> <span class="kw1">if</span><span class="br0">&#40;</span>x<span class="br0">&#41;</span>
2318
+ <span class="br0">&#123;</span>
2319
+ <span class="co1">//anyXml-generated-code</span>
2320
+ <span class="br0">&#125;</span></pre></div></p>
2321
+
2322
+ <p>Must follow an element that produces an if/elseif statement. Contains material that will be rendered if all preceding conditions are false, and the expression <code>x</code> evaluates to true.</p>
2323
+
2324
+ <h3 id="emptyelement">empty element</h3>
2325
+
2326
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml-1<span class="sc3"><span class="re1">&lt;else</span> <span class="re0">if</span>=<span class="st0">&quot;y&quot;</span><span class="re2">/&gt;</span></span>anyXml-2<span class="sc3"><span class="re1">&lt;else</span><span class="re2">/&gt;</span></span>anyXml-3<span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span></code></span>
2327
+ <div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">if</span><span class="br0">&#40;</span>x<span class="br0">&#41;</span>
2328
+ <span class="br0">&#123;</span>
2329
+ <span class="co1">//anyXml-1-generated-code</span>
2330
+ <span class="br0">&#125;</span>
2331
+ <span class="kw1">else</span> <span class="kw1">if</span><span class="br0">&#40;</span>y<span class="br0">&#41;</span>
2332
+ <span class="br0">&#123;</span>
2333
+ <span class="co1">//anyXml-2-generated-code</span>
2334
+ <span class="br0">&#125;</span>
2335
+ <span class="kw1">else</span>
2336
+ <span class="br0">&#123;</span>
2337
+ <span class="co1">//anyXml-3-generated-code</span>
2338
+ <span class="br0">&#125;</span></pre></div></p>
2339
+
2340
+ <p>Must be contained within an <code>&lt;if&gt;</code> or <code>&lt;test&gt;</code> element. The material following an empty <code>&lt;else/&gt;</code> element is treated as if it was contained within that element. If there are multiple <code>&lt;else/&gt;</code> elements all but the last one must have an <code>if=""</code> attribute.</p>
2341
+
2342
+ <hr />
2343
+
2344
+ <h2 id="elseif">elseif</h2>
2345
+
2346
+ <p>Forms a part of an if/elseif/else conditional structure.</p>
2347
+
2348
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;elseif</span> <span class="re0">condition</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/else<span class="re2">&gt;</span></span></span></code></span></p>
2349
+
2350
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">else</span> <span class="kw1">if</span><span class="br0">&#40;</span>x<span class="br0">&#41;</span>
2351
+ <span class="br0">&#123;</span>
2352
+ <span class="co1">//anyXml-generated-code</span>
2353
+ <span class="br0">&#125;</span></pre></div></p>
2354
+
2355
+ <p>Must follow an element that produces an if/elseif statement. Contains material that will be rendered if all preceding conditions are false, and the expression <code>x</code> evaluates to true.</p>
2356
+
2357
+ <hr />
2358
+
2359
+ <h2 id="for">for</h2>
2360
+
2361
+ <p>Iterates over a collection</p>
2362
+
2363
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var x in y&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></code></span></p>
2364
+
2365
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">foreach</span><span class="br0">&#40;</span><span class="kw4">var</span> x <span class="kw1">in</span> y<span class="br0">&#41;</span>
2366
+ <span class="br0">&#123;</span>
2367
+ <span class="co1">//anyXml-generated-code</span>
2368
+ <span class="br0">&#125;</span></pre></div></p>
2369
+
2370
+ <p>If the generated code appears to reference symbols named xIndex, xCount, xIsFirst, or xIsLast the minimum number of local variables needed will also be generated using a pattern similar to the following.</p>
2371
+
2372
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="br0">&#123;</span>
2373
+ <span class="kw4">int</span> xCount <span class="sy0">=</span> util_count_of<span class="br0">&#40;</span>y<span class="br0">&#41;</span><span class="sy0">;</span>
2374
+ <span class="kw4">int</span> xIndex <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span>
2375
+ <span class="kw4">bool</span> xIsFirst <span class="sy0">=</span> true<span class="sy0">;</span>
2376
+ <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="kw4">var</span> x <span class="kw1">in</span> y<span class="br0">&#41;</span>
2377
+ <span class="br0">&#123;</span>
2378
+ <span class="kw4">bool</span> xIsLast <span class="sy0">=</span> <span class="br0">&#40;</span>xIndex <span class="sy0">==</span> xCount <span class="sy0">-</span> <span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span>
2379
+ <span class="br0">&#123;</span>
2380
+ <span class="co1">//anyXml-generated-code</span>
2381
+ <span class="br0">&#125;</span>
2382
+ xIsFirst <span class="sy0">=</span> false<span class="sy0">;</span>
2383
+ xIndex<span class="sy0">++;</span>
2384
+ <span class="br0">&#125;</span>
2385
+ <span class="br0">&#125;</span></pre></div></p>
2386
+
2387
+ <h3 id="withassignments">with *="" assignments</h3>
2388
+
2389
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;for</span> <span class="re0">each</span>=<span class="st0">&quot;var x in y&quot;</span> <span class="re0">a</span>=<span class="st0">&quot;b&quot;</span> <span class="re0">c</span>=<span class="st0">&quot;d&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/for<span class="re2">&gt;</span></span></span></code></span></p>
2390
+
2391
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">foreach</span><span class="br0">&#40;</span><span class="kw4">var</span> x <span class="kw1">in</span> y<span class="br0">&#41;</span>
2392
+ <span class="br0">&#123;</span>
2393
+ a<span class="sy0">=</span>b<span class="sy0">;</span>
2394
+ c<span class="sy0">=</span>d<span class="sy0">;</span>
2395
+ <span class="co1">//anyXml-generated-code</span>
2396
+ <span class="br0">&#125;</span></pre></div></p>
2397
+
2398
+ <hr />
2399
+
2400
+ <h2 id="global">global</h2>
2401
+
2402
+ <p>Declares a property that's available to all templates while rendering.</p>
2403
+
2404
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;global</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;t&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2405
+
2406
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">object</span> _x <span class="sy0">=</span> a<span class="sy0">;</span>
2407
+ <span class="kw1">public</span> <span class="kw4">object</span> x <span class="br0">&#123;</span>get <span class="br0">&#123;</span><span class="kw1">return</span> _x<span class="sy0">;</span><span class="br0">&#125;</span> set <span class="br0">&#123;</span>_x <span class="sy0">=</span> value<span class="sy0">;</span><span class="br0">&#125;</span><span class="br0">&#125;</span>
2408
+ &nbsp;
2409
+ <span class="kw4">object</span> _y <span class="sy0">=</span> b<span class="sy0">;</span>
2410
+ <span class="kw1">public</span> <span class="kw4">object</span> y <span class="br0">&#123;</span>get <span class="br0">&#123;</span><span class="kw1">return</span> _y<span class="sy0">;</span><span class="br0">&#125;</span> set <span class="br0">&#123;</span>_y <span class="sy0">=</span> value<span class="sy0">;</span><span class="br0">&#125;</span><span class="br0">&#125;</span></pre></div></p>
2411
+
2412
+ <p>Although object seems like an inconvenient type, it works quite well when used in simple value assignments like <code>&lt;set x="42"/&gt;</code> and expression output like <code>${x}</code>.</p>
2413
+
2414
+ <h3 id="withtype-1">with type=""</h3>
2415
+
2416
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;global</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;t&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2417
+
2418
+ <p><div class="geshifilter"><pre class="geshifilter-csharp">t _x <span class="sy0">=</span> a<span class="sy0">;</span>
2419
+ <span class="kw1">public</span> t x <span class="br0">&#123;</span>get <span class="br0">&#123;</span><span class="kw1">return</span> _x<span class="sy0">;</span><span class="br0">&#125;</span> set <span class="br0">&#123;</span>_x <span class="sy0">=</span> value<span class="sy0">;</span><span class="br0">&#125;</span><span class="br0">&#125;</span>
2420
+ &nbsp;
2421
+ t _y <span class="sy0">=</span> b<span class="sy0">;</span>
2422
+ <span class="kw1">public</span> t y <span class="br0">&#123;</span>get <span class="br0">&#123;</span><span class="kw1">return</span> _y<span class="sy0">;</span><span class="br0">&#125;</span> set <span class="br0">&#123;</span>_y <span class="sy0">=</span> value<span class="sy0">;</span><span class="br0">&#125;</span><span class="br0">&#125;</span></pre></div></p>
2423
+
2424
+ <hr />
2425
+
2426
+ <h2 id="if">if</h2>
2427
+
2428
+ <p>Forms a part of an if/elseif/else conditional structure.</p>
2429
+
2430
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;if</span> <span class="re0">condition</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/if<span class="re2">&gt;</span></span></span></code></span></p>
2431
+
2432
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">if</span><span class="br0">&#40;</span>x<span class="br0">&#41;</span>
2433
+ <span class="br0">&#123;</span>
2434
+ <span class="co1">//anyXml-generated-code</span>
2435
+ <span class="br0">&#125;</span></pre></div></p>
2436
+
2437
+ <p>Material in an <code>if</code> element will only render if the condition evaluates to true.</p>
2438
+
2439
+ <p>Alias: <code>&lt;test if=""&gt;</code></p>
2440
+
2441
+ <hr />
2442
+
2443
+ <h2 id="include">include</h2>
2444
+
2445
+ <p>TODO: forgot to write up this one</p>
2446
+
2447
+ <hr />
2448
+
2449
+ <h2 id="macro">macro</h2>
2450
+
2451
+ <p>Declares a member helper function available to all templates while rendering.</p>
2452
+
2453
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;macro</span> <span class="re0">name</span>=<span class="st0">&quot;anyName&quot;</span> <span class="re0">x</span>=<span class="st0">&quot;t1&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;t2&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/macro<span class="re2">&gt;</span></span></span></code></span></p>
2454
+
2455
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw4">string</span> anyName<span class="br0">&#40;</span>t1 x, t2 y<span class="br0">&#41;</span>
2456
+ <span class="br0">&#123;</span>
2457
+ <span class="co1">//anyXml-generated-code</span>
2458
+ <span class="br0">&#125;</span></pre></div></p>
2459
+
2460
+ <p>Macros may be used invoked as part of an output expression <code>${anyName(a,b)}</code> or anyplace else code appears like <code>&lt;set z="anyName(a,b)"/&gt;</code> or <code># z=anyName(a,b);</code></p>
2461
+
2462
+ <hr />
2463
+
2464
+ <h2 id="render">render</h2>
2465
+
2466
+ <p>Within a partial file, renders the material wrapped by the reference to that partial file.</p>
2467
+
2468
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml">anyXml2<span class="sc3"><span class="re1">&lt;render</span><span class="re2">/&gt;</span></span>anyXml4</code></span></p>
2469
+
2470
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName<span class="re2">&gt;</span></span></span>anyXml3<span class="sc3"><span class="re1">&lt;/partialFileName<span class="re2">&gt;</span></span></span>anyXml5</code></span></p>
2471
+
2472
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2473
+ <span class="br0">&#123;</span>
2474
+ <span class="co1">//anyXml2-generated-code</span>
2475
+ <span class="br0">&#123;</span>
2476
+ <span class="co1">//anyXml3-generated-code</span>
2477
+ <span class="br0">&#125;</span>
2478
+ <span class="co1">//anyXml4-generated-code</span>
2479
+ <span class="br0">&#125;</span>
2480
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2481
+
2482
+ <p>When <code>&lt;render/&gt;</code> appears in a partial template it generates code for the contents of the element which referenced the partial. This can be used to have a partial file which "wraps" any sort of contained material in the parent template. This enabled partials to be used as content wrappers to produce rounded corners, ajax effects, around arbirtary content.</p>
2483
+
2484
+ <h3 id="withsection">with section=""</h3>
2485
+
2486
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml">anyXml2<span class="sc3"><span class="re1">&lt;render</span> <span class="re0">section</span>=<span class="st0">&quot;anyName&quot;</span><span class="re2">/&gt;</span></span>anyXml4</code></span></p>
2487
+
2488
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;section</span> <span class="re0">name</span>=<span class="st0">&quot;anyName&quot;</span><span class="re2">&gt;</span></span>anyXml3<span class="sc3"><span class="re1">&lt;/section<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/partialFileName<span class="re2">&gt;</span></span></span>anyXml5</code></span></p>
2489
+
2490
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2491
+ <span class="br0">&#123;</span>
2492
+ <span class="co1">//anyXml2-generated-code</span>
2493
+ <span class="br0">&#123;</span>
2494
+ <span class="co1">//anyXml3-generated-code</span>
2495
+ <span class="br0">&#125;</span>
2496
+ <span class="co1">//anyXml4-generated-code</span>
2497
+ <span class="br0">&#125;</span>
2498
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2499
+
2500
+ <p>When <code>&lt;render section=""/&gt;</code> appears in a partial template it renders the contents of the <code>&lt;section name=""&gt;</code> contained in the referencing <code>&lt;render partial=""&gt;</code> template. This enables partials to render several distinct micro-templates, for example a repeater partial could have top/bottom/even/odd named sections.</p>
2501
+
2502
+ <p>See also: <code>&lt;section/&gt;</code></p>
2503
+
2504
+ <h3 id="withassignments-1">with *="" assignments</h3>
2505
+
2506
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml">anyXml2<span class="sc3"><span class="re1">&lt;render</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span><span class="re2">/&gt;</span></span>anyXml4</code></span></p>
2507
+
2508
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName<span class="re2">&gt;</span></span></span>anyXml3<span class="sc3"><span class="re1">&lt;/partialFileName<span class="re2">&gt;</span></span></span>anyXml5</code></span></p>
2509
+
2510
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2511
+ <span class="br0">&#123;</span>
2512
+ <span class="co1">//anyXml2-generated-code</span>
2513
+ <span class="br0">&#123;</span>
2514
+ <span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2515
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span>
2516
+ <span class="co1">//anyXml3-generated-code</span>
2517
+ <span class="br0">&#125;</span>
2518
+ <span class="co1">//anyXml4-generated-code</span>
2519
+ <span class="br0">&#125;</span>
2520
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2521
+
2522
+ <p>Partial files may declare local variables when rendering passed in content. They are available to the scope of the wrapped content or named section in the outer template file.</p>
2523
+
2524
+ <h3 id="withfallbackcontent">with fallback content</h3>
2525
+
2526
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml">anyXml2<span class="sc3"><span class="re1">&lt;render</span> <span class="re0">section</span>=<span class="st0">&quot;anyName&quot;</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span><span class="re2">&gt;</span></span>anyXml-fallback<span class="sc3"><span class="re1">&lt;/render<span class="re2">&gt;</span></span></span>anyXml4</code></span></p>
2527
+
2528
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName</span><span class="re2">/&gt;</span></span>anyXml5</code></span></p>
2529
+
2530
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2531
+ <span class="br0">&#123;</span>
2532
+ <span class="co1">//anyXml2-generated-code</span>
2533
+ <span class="br0">&#123;</span>
2534
+ <span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2535
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span>
2536
+ <span class="co1">//anyXml-fallback-generated-code</span>
2537
+ <span class="br0">&#125;</span>
2538
+ <span class="co1">//anyXml4-generated-code</span>
2539
+ <span class="br0">&#125;</span>
2540
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2541
+
2542
+ <p>When the reference to a partial file is empty, or the named section does not exist, the contents of the <code>&lt;render&gt;</code> element in the partial file will generate the rendering code by default.</p>
2543
+
2544
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName<span class="re2">&gt;</span></span></span>anyXml3<span class="sc3"><span class="re1">&lt;/partialFileName<span class="re2">&gt;</span></span></span>anyXml5</code></span></p>
2545
+
2546
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2547
+ <span class="br0">&#123;</span>
2548
+ <span class="co1">//anyXml2-generated-code</span>
2549
+ <span class="br0">&#123;</span>
2550
+ <span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2551
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span>
2552
+ <span class="co1">//anyXml3-generated-code</span>
2553
+ <span class="br0">&#125;</span>
2554
+ <span class="co1">//anyXml4-generated-code</span>
2555
+ <span class="br0">&#125;</span>
2556
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2557
+
2558
+ <p>When the reference to a partial file has contents, the contents of the <code>&lt;render&gt;</code> element in the partial file is unused.</p>
2559
+
2560
+ <hr />
2561
+
2562
+ <h2 id="renderpartial">render partial=""</h2>
2563
+
2564
+ <p>Includes the contents of a partial file for rendering at the point where it appears.</p>
2565
+
2566
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;render</span> <span class="re0">partial</span>=<span class="st0">&quot;_partialFileName&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2567
+
2568
+ <p>Alias: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;partialFileName</span><span class="re2">/&gt;</span></span></code></span></p>
2569
+
2570
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="br0">&#123;</span>
2571
+ <span class="co1">//_partialFileName.spark-generated-code</span>
2572
+ <span class="br0">&#125;</span></pre></div></p>
2573
+
2574
+ <p>Partial files may have any name, but usually start with _ by convention. The name without the underscore may be used as a short version of the <code>&lt;render/&gt;</code> element.</p>
2575
+
2576
+ <h3 id="withassignments-2">with *="" assignments</h3>
2577
+
2578
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;render</span> <span class="re0">partial</span>=<span class="st0">&quot;_partialFileName&quot;</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2579
+
2580
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="br0">&#123;</span>
2581
+ <span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2582
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span>
2583
+ <span class="co1">//_partialFileName.spark-generated-code</span>
2584
+ <span class="br0">&#125;</span></pre></div></p>
2585
+
2586
+ <p>A partial file reference may declare local variables. They are available to the scope of the wrapped content or named section.</p>
2587
+
2588
+ <hr />
2589
+
2590
+ <h2 id="section">section</h2>
2591
+
2592
+ <p>Declares a section of material passed in to a partial file reference.</p>
2593
+
2594
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;section</span> <span class="re0">name</span>=<span class="st0">&quot;anyName&quot;</span><span class="re2">&gt;</span></span>anyXml3<span class="sc3"><span class="re1">&lt;/section<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/partialFileName<span class="re2">&gt;</span></span></span>anyXml5</code></span></p>
2595
+
2596
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml2<span class="sc3"><span class="re1">&lt;render</span> <span class="re0">section</span>=<span class="st0">&quot;anyName&quot;</span><span class="re2">/&gt;</span></span>anyXml4</code></span></p>
2597
+
2598
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2599
+ <span class="br0">&#123;</span>
2600
+ <span class="co1">//anyXml2-generated-code</span>
2601
+ <span class="br0">&#123;</span>
2602
+ <span class="co1">//anyXml3-generated-code</span>
2603
+ <span class="br0">&#125;</span>
2604
+ <span class="co1">//anyXml4-generated-code</span>
2605
+ <span class="br0">&#125;</span>
2606
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2607
+
2608
+ <p>When <code>&lt;render section=""/&gt;</code> appears in a partial template it renders the contents of the <code>&lt;section name=""&gt;</code> contained in the referencing <code>&lt;render partial=""&gt;</code> template. This enables partials to render several distinct micro-templates, for example a repeater partial could have top/bottom/even/odd named sections.</p>
2609
+
2610
+ <h3 id="withassignments-3">with *="" assignments</h3>
2611
+
2612
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml">anyXml1<span class="sc3"><span class="re1">&lt;partialFileName<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;section</span> <span class="re0">name</span>=<span class="st0">&quot;anyName&quot;</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span><span class="re2">&gt;</span></span>anyXml3<span class="sc3"><span class="re1">&lt;/section<span class="re2">&gt;</span></span></span><span class="sc3"><span class="re1">&lt;/partialFileName<span class="re2">&gt;</span></span></span>anyXml5</code></span></p>
2613
+
2614
+ <p>Given: <span class="geshifilter"><code class="geshifilter-xml">anyXml2<span class="sc3"><span class="re1">&lt;render</span> <span class="re0">section</span>=<span class="st0">&quot;anyName&quot;</span><span class="re2">/&gt;</span></span>anyXml4</code></span></p>
2615
+
2616
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="co1">//anyXml1-generated-code</span>
2617
+ <span class="br0">&#123;</span>
2618
+ <span class="co1">//anyXml2-generated-code</span>
2619
+ <span class="br0">&#123;</span>
2620
+ <span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2621
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span>
2622
+ <span class="co1">//anyXml3-generated-code</span>
2623
+ <span class="br0">&#125;</span>
2624
+ <span class="co1">//anyXml4-generated-code</span>
2625
+ <span class="br0">&#125;</span>
2626
+ <span class="co1">//anyXml5-generated-code</span></pre></div></p>
2627
+
2628
+ <hr />
2629
+
2630
+ <h2 id="set">set</h2>
2631
+
2632
+ <p>Assigns an expression to a variable.</p>
2633
+
2634
+ <p>Usage: <set x="a" y="b"/></p>
2635
+
2636
+ <p><div class="geshifilter"><pre class="geshifilter-csharp">x <span class="sy0">=</span> a<span class="sy0">;</span>
2637
+ y <span class="sy0">=</span> b<span class="sy0">;</span></pre></div></p>
2638
+
2639
+ <p>This is arguably the least interesting element in the entire Spark library. But if it wasn't there you'd probably have to escape assignments into code fragments like <code>#x = a;</code>. So there you go.</p>
2640
+
2641
+ <hr />
2642
+
2643
+ <h2 id="test">test</h2>
2644
+
2645
+ <p>Forms a part of an if/elseif/else conditional structure.</p>
2646
+
2647
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;test</span> <span class="re0">if</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml<span class="sc3"><span class="re1">&lt;/test<span class="re2">&gt;</span></span></span></code></span></p>
2648
+
2649
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">if</span><span class="br0">&#40;</span>x<span class="br0">&#41;</span>
2650
+ <span class="br0">&#123;</span>
2651
+ <span class="co1">//anyXml-generated-code</span>
2652
+ <span class="br0">&#125;</span></pre></div></p>
2653
+
2654
+ <p>Material in a <code>test</code> element will only render if the condition evaluates to true.</p>
2655
+
2656
+ <p>Alias: <code>&lt;if condition=""&gt;</code></p>
2657
+
2658
+ <hr />
2659
+
2660
+ <h2 id="useassembly">use assembly=""</h2>
2661
+
2662
+ <p>Ensures a partially or fully qualified assembly name is include when the Spark assembly is compiled.</p>
2663
+
2664
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">assembly</span>=<span class="st0">&quot;system.something.something&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2665
+
2666
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">assembly</span>=<span class="st0">&quot;system.something.something, etc=20394824, etc=239483432&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2667
+
2668
+ <hr />
2669
+
2670
+ <h2 id="usecontent">use content=""</h2>
2671
+
2672
+ <p>Renders whatever has been captured in a named content spool.</p>
2673
+
2674
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;x&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2675
+
2676
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">if</span> <span class="br0">&#40;</span>Contents.<span class="me1">ContainsKey</span><span class="br0">&#40;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
2677
+ <span class="br0">&#123;</span>
2678
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>Contents<span class="br0">&#91;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
2679
+ <span class="br0">&#125;</span></pre></div></p>
2680
+
2681
+ <p>The use of content spooling is actually very efficient. It uses pooled pages of string references to replay the original output, which doesn't increase memory pressure and avoids string copying and concatination costs.</p>
2682
+
2683
+ <p>There is a built-in content spool named "view".</p>
2684
+
2685
+ <h3 id="withfallbackcontent-1">with fallback content</h3>
2686
+
2687
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">content</span>=<span class="st0">&quot;x&quot;</span><span class="re2">&gt;</span></span>anyXml-fallback<span class="sc3"><span class="re1">&lt;/use<span class="re2">&gt;</span></span></span></code></span></p>
2688
+
2689
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">if</span> <span class="br0">&#40;</span>Contents.<span class="me1">ContainsKey</span><span class="br0">&#40;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
2690
+ <span class="br0">&#123;</span>
2691
+ Output.<span class="me1">Write</span><span class="br0">&#40;</span>Contents<span class="br0">&#91;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
2692
+ <span class="br0">&#125;</span>
2693
+ <span class="kw1">else</span>
2694
+ <span class="br0">&#123;</span>
2695
+ <span class="co1">// anyXml-fallback-generated-code</span>
2696
+ <span class="br0">&#125;</span></pre></div></p>
2697
+
2698
+ <p>If the named content section has never been written into the fallback output is generated. This can be used for default title contents, for example <code>&lt;title&gt;&lt;use content="title"&gt;My Default Title&lt;/use&gt;&lt;/content&gt;</code>, or for wrapping any html in the layout you may want to entirely replace in some views.</p>
2699
+
2700
+ <hr />
2701
+
2702
+ <h2 id="usefile">use file=""</h2>
2703
+
2704
+ <p>An alias for <code>&lt;render partial=""/&gt;</code>.</p>
2705
+
2706
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">file</span>=<span class="st0">&quot;_partialFileName&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2707
+
2708
+ <p>All behavior is identical to render partial.</p>
2709
+
2710
+ <hr />
2711
+
2712
+ <h2 id="useimport">use import=""</h2>
2713
+
2714
+ <p>Includes all of the elements which have a global effect declared in a template.</p>
2715
+
2716
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">import</span>=<span class="st0">&quot;fileName&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2717
+
2718
+ <p>This can be used to organize elements like <code>&lt;viewdata/&gt;</code>, <code>&lt;global/&gt;</code>, <code>&lt;macro/&gt;</code>, <code>&lt;use import=""/&gt;</code>, <code>&lt;use assembly=""/&gt;</code>, <code>&lt;use namespace=""/&gt;</code> into importable template files for greater manageability.</p>
2719
+
2720
+ <p>The well-known file named <code>_global.spark</code> in the current template's directory, and in the Shared directory, is automatically imported.</p>
2721
+
2722
+ <hr />
2723
+
2724
+ <h2 id="usemaster">use master=""</h2>
2725
+
2726
+ <p>Forces the layout around the current template file to become the named file.</p>
2727
+
2728
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">master</span>=<span class="st0">&quot;fileName&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2729
+
2730
+ <p>This will override the master which would normally have been used. Multi-level rendering can be accomplished by chaining templates with use master="" elements.</p>
2731
+
2732
+ <p>This element has no effect when it's in a partial file or import file.</p>
2733
+
2734
+ <hr />
2735
+
2736
+ <h2 id="usenamespace">use namespace=""</h2>
2737
+
2738
+ <p>Uses a dotnet namespace in the generated code.</p>
2739
+
2740
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;use</span> <span class="re0">namespace</span>=<span class="st0">&quot;any.name.space&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2741
+
2742
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">using</span> <span class="co3">any.name.space</span><span class="sy0">;</span></pre></div></p>
2743
+
2744
+ <p>Uses a namespace. Frequently placed in an import file like _global.spark.</p>
2745
+
2746
+ <hr />
2747
+
2748
+ <h2 id="var">var</h2>
2749
+
2750
+ <p>Declares a local variables and it's initialization expression.</p>
2751
+
2752
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2753
+
2754
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw4">var</span> x <span class="sy0">=</span> a<span class="sy0">;</span>
2755
+ <span class="kw4">var</span> y <span class="sy0">=</span> b<span class="sy0">;</span></pre></div></p>
2756
+
2757
+ <h3 id="withtype-2">with type=""</h3>
2758
+
2759
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;var</span> <span class="re0">x</span>=<span class="st0">&quot;a&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;b&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;t&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2760
+
2761
+ <p><div class="geshifilter"><pre class="geshifilter-csharp">t x <span class="sy0">=</span> a<span class="sy0">;</span>
2762
+ t y <span class="sy0">=</span> b<span class="sy0">;</span></pre></div></p>
2763
+
2764
+ <hr />
2765
+
2766
+ <h2 id="viewdata">viewdata</h2>
2767
+
2768
+ <p>Declares an accessor property for a piece of view data.</p>
2769
+
2770
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">x</span>=<span class="st0">&quot;t1&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;t2&quot;</span> <span class="re2">/&gt;</span></span></code></span></p>
2771
+
2772
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> t1 x <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="br0">&#40;</span>t1<span class="br0">&#41;</span>ViewData.<span class="me1">Eval</span><span class="br0">&#40;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span>
2773
+ <span class="kw1">public</span> t2 y <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="br0">&#40;</span>t2<span class="br0">&#41;</span>ViewData.<span class="me1">Eval</span><span class="br0">&#40;</span><span class="st0">&quot;y&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span></pre></div></p>
2774
+
2775
+ <h3 id="withdefault">with default=""</h3>
2776
+
2777
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">x</span>=<span class="st0">&quot;t1&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;t2&quot;</span> <span class="re0">default</span>=<span class="st0">&quot;d&quot;</span><span class="re2">/&gt;</span></span></code></span></p>
2778
+
2779
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> t1 x <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="br0">&#40;</span>t1<span class="br0">&#41;</span><span class="br0">&#40;</span>ViewData.<span class="me1">Eval</span><span class="br0">&#40;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#41;</span> <span class="sy0">??</span> d<span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span>
2780
+ <span class="kw1">public</span> t2 y <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="br0">&#40;</span>t2<span class="br0">&#41;</span><span class="br0">&#40;</span>ViewData.<span class="me1">Eval</span><span class="br0">&#40;</span><span class="st0">&quot;y&quot;</span><span class="br0">&#41;</span> <span class="sy0">??</span> d<span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span></pre></div></p>
2781
+
2782
+ <p>Adds a fallback value for the property in cases where the actual view data is missing or null.</p>
2783
+
2784
+ <h3 id="withpropertyname">with property name</h3>
2785
+
2786
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">x</span>=<span class="st0">&quot;t1 anyName1&quot;</span> <span class="re0">y</span>=<span class="st0">&quot;t2 anyName2&quot;</span> <span class="re2">/&gt;</span></span></code></span></p>
2787
+
2788
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> t1 anyName1 <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="br0">&#40;</span>t1<span class="br0">&#41;</span>ViewData.<span class="me1">Eval</span><span class="br0">&#40;</span><span class="st0">&quot;x&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span>
2789
+ <span class="kw1">public</span> t2 anyName2 <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="br0">&#40;</span>t2<span class="br0">&#41;</span>ViewData.<span class="me1">Eval</span><span class="br0">&#40;</span><span class="st0">&quot;y&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span></pre></div></p>
2790
+
2791
+ <p>A name following the type will determine the name of the property which is added. This enables you to declare
2792
+ viewdata accessors which contain dashes or dots, which are not allowed in property names.</p>
2793
+
2794
+ <hr />
2795
+
2796
+ <h2 id="viewdatamodel">viewdata model=""</h2>
2797
+
2798
+ <p>Provides a generic parameter to strongly type the Model of the view's base class.</p>
2799
+
2800
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">model</span>=<span class="st0">&quot;t1&quot;</span> <span class="re2">/&gt;</span></span></code></span></p>
2801
+
2802
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw4">class</span> generated_view_name <span class="sy0">:</span> base_view_name<span class="sy0">&lt;</span>t1<span class="sy0">&gt;</span>
2803
+ <span class="br0">&#123;</span>
2804
+ <span class="kw1">public</span> t1 Model <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> ViewData.<span class="me1">Model</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span>
2805
+ <span class="br0">&#125;</span></pre></div></p>
2806
+
2807
+ <p>The base view class is strongly typed, and a typed property named Model is added to the generated view.</p>
2808
+
2809
+ <h3 id="withpropertyname-1">with property name</h3>
2810
+
2811
+ <p>Usage: <span class="geshifilter"><code class="geshifilter-xml"><span class="sc3"><span class="re1">&lt;viewdata</span> <span class="re0">model</span>=<span class="st0">&quot;t1 anyName&quot;</span> <span class="re2">/&gt;</span></span></code></span></p>
2812
+
2813
+ <p><div class="geshifilter"><pre class="geshifilter-csharp"><span class="kw1">public</span> <span class="kw4">class</span> generated_view_name <span class="sy0">:</span> base_view_name<span class="sy0">&lt;</span>t1<span class="sy0">&gt;</span>
2814
+ <span class="br0">&#123;</span>
2815
+ <span class="kw1">public</span> t1 Model <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> ViewData.<span class="me1">Model</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span>
2816
+ <span class="kw1">public</span> t1 anyName <span class="br0">&#123;</span> get <span class="br0">&#123;</span> <span class="kw1">return</span> ViewData.<span class="me1">Model</span><span class="sy0">;</span> <span class="br0">&#125;</span> <span class="br0">&#125;</span>
2817
+ <span class="br0">&#125;</span></pre></div></p>
2818
+
2819
+ <p>A name following the type causes an additional property of that name to be added as an alias for the Model property.</p>
2820
+
2821
+ <hr />
2822
+
2823
+ <h2 id="Seealsosourcecode">See also: source code</h2>
2824
+
2825
+ <p>The above is based on code in the following files.</p>
2826
+
2827
+ <p><a href="http://github.com/loudej/spark/blob/master/src/Spark/Compiler/NodeVisitors/ChunkBuilderVisitor.cs">ChunkBuilderVisitor.cs</a></p>
2828
+
2829
+ <p><a href="http://github.com/loudej/spark/blob/master/src/Spark/Compiler/CSharp/ChunkVisitors/GeneratedCodeVisitor.cs">GeneratedCodeVisitor.cs</a></p>
2830
+ </div>
2831
+ </div>
2832
+ </div>
2833
+
2834
+ </body>
2835
+ </html>