Plugin note
This functionality is contained within an expression evaluator plugin. As such, it is available only when the corresponding plugin is installed.
Plugin assembly
CSF.Zpt.ExpressionEvaluators.CSharpExpressions.dll
Plugin class
CSF.Zpt.ExpressionEvaluators.CSharpExpressions.CSharpExpressionEvaluator
Expression prefix
csharp:
TALES 'csharp' expressions
csharp:
expressions permit the use of C♯ as a mechanism of evaluating TALES expressions.
The provided C♯ expression string is executed, its value determined and returned as the result of the
expression.
Permitted expressions
C♯ expressions supported by this plugin must be single statements. Multiple statements (joined by semicolons)
are not permitted and will not compile.
Expressions have access to all of the variables which are available to TALES, including those created by
tal:define
and tal:repeat
attributes.
In essence, to determine whether an expression is OK or not, consider whether it would be valid for
execution if preceded by a return
keyword and followed by a semicolon, assuming that all of the
TALES variables are also available in the same scope:
return YOUR_EXPRESSION_HERE;
Example
<div tal:define="myName string:sally">
Hello, my name is
<span tal:replace="csharp:myName.ToUpperInvariant()">JOSEPH</span>
</div>
The expression above would emit Hello, my name is SALLY, surrounded with HTML <div>
tags.
Note on variable names
If this plugin is installed (by default, it is) then all variable names created through
tal:define
or tal:repeat
must also be valid C♯ variable names.
For example, on its own, the TALES specification would permit a variable named 12things;
this is not a valid C♯ variable name though.
If such a variable is 'in scope' when a csharp:
expression is evaluated, the expression will
not compile and an error will be raised.
It does not matter whether the C♯ expression attempts to make use of such a 'bad' variable or not.
The very presence of the variable in the TALES environment will prevent the C♯ expression from compiling.
Reminder: HTML encoding
Because TALES expressions (including C♯ expressions) are specified within the source document, in the source document's own syntax, you must adhere to that document's escaping/encoding rules. In particular this applies to double-quote characters, which must be specified as ", greater-than (>), less-than (<) and ampersands (&).
This is illustrated in the following example, where DateTime.ToString
is used with a
string parameter to get a custom date format.
<p tal:define="today csharp:DateTime.Today">
Today's date is
<span tal:content="csharp:today.ToString("yyyy-MM-dd")">2012-01-01<span>
</p>
Expression internals & limitations
Internally, to provide C♯ expressions, the CodeDOM API is used. Each expression is compiled into a generated class, in an in-memory .NET assembly.
Each TALES variable which is in-scope for the expression is provided as a private member field
of that class. To simplify variable access these private fields are typed using the dynamic
keyword. This means that for general usage their type does not need to known.
A limitation of this approach is exposed when you wish to use extension methods, including
Linq, such as .Sum()
or .Count()
. These are incompatible with dynamically-typed
variables. For example, if you wrote some markup such as the following example:
<p tal:define="itemCount csharp:here.Items.Count(x => x.Colour == "Red")">
There are <span tal:replace="itemCount">3</span> red items
<p>
This expression will not compile because the .Count()
method from Linq is an extension
method which requires a strongly-typed (and not dynamically-typed) reference.
There are two available ways to work around/deal with this limitation:
Consider moving expressions into your model
The recommended and simplest way to deal with this limitation is to move that expression into your MVC model
class as either a property or plain method call. This functionality in the model may then make use of
extension methods/linq/etc and expose the result to the view. No special code or technique need be used here,
simply a method on the model such as public int GetItemCount(string colour)
.
This also guides you towards pushing any 'logic' of your model into the model itself, which is good practice.
Specify types, namespace imports and assembly references
For scenarios where moving the code into your model is not possible (for example, if you do not control the model type), ZPT-Sharp provides an advanced mechanism for solving 'the extension method' problem. This solution is a set of three special expression types (and related configuration) which allow you to specify the .NET type of your TALES variables, as well as import namespaces and provide references to other assemblies.
These advanced topics are covered in documentation for the additional expression types as well as documentation for the configuration options which affect them.