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 &quot;, greater-than (&gt;), less-than (&lt;) and ampersands (&amp;).

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(&quot;yyyy-MM-dd&quot;)">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 == &quot;Red&quot;)">
  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.