AppFrame

Razor documentation

Web4 offers dynamic server-side pages based on the Razor templating engine.

The officially sanctioned scenario is to use it to enumerate data and generate HTML on the server. It should never be used to implement interactivity and server-side logic.

At a glance

Access article data:

  • Article ID: @Article.Id → razor.002
  • Parent ID: @Article.ParentId → web4
  • Title: @Article.Title → Razor documentation
  • Author: @Article.Author → Schmidt, Jarl Erik
  • Summary: @Article.Summary →
  • List of files: @Article.Files

Misc:

  • Site language: @Language → EN
  • Localize string: @Localize("hello") → hello
  • Breadcrumb: @Breadcrumb() → AppFrame > Web > Web 4 > Razor documentation
  • Link to another page on the site: @Link("login") → Article not found: login
  • Start a HTML element: @Begin("li") → <li>
  • End a HTML element: @End("li") → </li>
  • HTML-encode a string: @HtmlEncode("<") → <
  • URL-encode a string: @UrlEncode("?") → "%3f"
  • Javascript-encode a string: [" '] → "\" and \u0027"

Meta stuff:

  • User script: @ClientSide.User
  • Script placeholder: @Scripts.PlaceHolder

Getting data

Enumerate a data source:

  • @* Example: *@
    <ul>
    @foreach (var row in GetRows("dsPeople")) {
    <li>@row["Name"]</ li>
    }
    </ul>
    
  • Returns a DataTableWrapper

Execute a stored procedure:

  • The function takes a procedure name, followed by a parameter array. The size of the parameter array is required to be even. The item at 0 and following even indexes are expected to be alphanumeric strings and will be used as parameter names in calling the procedure, while items at odd indexes will be the parameter values.
  • Note: Parameter names should NEVER come from the query string
  • Note: Parameter names will be validated, and an exception will be thrown if they contain non-alphanumeric characters!
  • @* Example: *@
    @{
        var data = ExecProcedure("procDoStuff", "para1", 20, "para2", 30);
    }
    <ul>
    @foreach (var row in data[0]) {
        <li>@row["Name"]</ li>
    }
    </ul>
    
  • Returns a ProcedureResult

Data related classes

ProcedureResult

  • Contains the data tables resulting from a procedure call
  • Properties:

DataTableWrapper

  • Provides access to the rows in a data table from from an GetRows or ExecProcedure call.
  • Properties:
    • RowWrapper Item[int pIndex] - Returns the row at the given index (default property)
    • IEnumerable<RowWrapper> Rows - Returns an enumeration of the rows in the table, the DataTableWrapper class also implements IEnumerable<RowWrapper>
    • int Count - Returns the number of rows
    • DataColumnCollection Columns - Returns the collection of table columns
  • Methods:
    • RowWrapper[] Select() - Returns an array of all the rows in the table
    • RowWrapper[] Select(String pFilter) - Returns an array of rows matching the filter
    • RowWrapper[] Select(String pFilter, String sort) - Returns an array of rows matching the filter, sorted by sort expression
    • RowWrapper FindRow(String pColumnName, String pSearchKey) - Returns a single row where the column matches the key
    • RowWrapper FindRow(String[] pColumnNames, String[] pSearchKeys) - Returns a single row where the columns matches the keys

RowWrapper

  • Provides access to the values of a data row in a table. The class inherits DynamicObject and provides two ways to access the data of a row. Note in the example below that the dynamic type is used in the variable declaration for the latter:
    • @* DataRow-style column value access: *@
      
      @foreach (var item in GetData("dsPeople") {
          @row["LastName"], @row["FirstName"]
      }
      
      @* Dynamic column value access: *@
      
      @foreach (dynamic item in GetData("dsPeople") {
          @row.Lastname, @row.FirstName
      }
      
  • Properties:
    • Object Item[int pIndex] - Returns the value at the given column index (default property)
    • Object Item[String pName] - Returns the value of the named column (default property)
    • int RowIndex - Returns the index of the row inside the parent table
  • Methods:
    • bool IsNull(int pIndex) - Checks if the value of the given column index is DbNull
    • bool IsNull(String pColumnName) - Checks if the value of the named column is DbNull
    • RowWrapper[] GetChildRows(String pChildName) - Returns the rows from a named child datasource matched with this row from a master datasource

Session variables (requires login)

  • Username: @User.ShortName
  • Culture: @User.Culture
  • Browser: @User.Browser

Query string parameters

Note: The Razor functionality is only provided for data enumeration. Query string values should never be used for other scenarios than "drilling down" on data!

Type checks

  • x is integer? @QueryString.ContainsInteger("x") → False
  • y is decimal? @QueryString.ContainsDecimal("y") → False
  • z is alphanumeric? @QueryString.ContainsAlphanumeric("z") → False
  • z is a list? @QueryString.ContainsList("z") → False
  • Verification using regular expression: @QueryString.Contains("x", "^\w+\\w+\.\w+$") → False

Checking several things at once

  • x, y and z are all provided? @QueryString.ContainsAll("x", "y", "z") → False
  • x, y and z are all integers? @QueryString.ContainsIntegers("x", "y", "z") → False
  • x, y and z are all decimals? @QueryString.ContainsDecimals("x", "y", "z") → False
  • x, y and z are all alphanumeric? @QueryString.ContainsAlphanumerics("x", "y", "z") → False
  • x, y and z are all lists? @QueryString.ContainsLists("x", "y", "z") → False

Security

  • @QueryString.RawValue() gives UNESCAPED querystring parameters and opens for possible XSS!
  • When using the RawValue accessor, always check using a regular expression!
  • Should always be escaped when used in Razor: @HtmlEncode(@QueryString.RawValue("x")) →
  • Best practice: Use "verifying" accessors:
    • Integer: @QueryString.IntValue("parameter") - Digits
    • Decimals: @QueryString.DecimalValue("parameter") - Digits followed by optional period and more digits
    • Alphanumeric: @QueryString.Alphanumeric("parameter") - A-Z, a-z and 0-9
    • List: @QueryString.List("parameter") - Alphanumeric characters and comma
  • Best practice: The verifying accessors throw exceptions upon invalid values, so use checks described above before using them

Using querystring parameters to filter data

String comparisons

  • @Where.Contains("Login", "x").GetRows("dsUsers");
    • Resulting filter: [Login] LIKE '%' + @parameter + '%'
  • @Where.IsEqual("Login", "x").GetRows("dsUsers");
    • Resulting filter: [Login] = @parameter

Numeric comparisons

  • @Where.GreaterThan("TimeZoneCode", "x").GetRows("dsUsers");
    • Resulting filter: [TimeZoneCode] < @parameter
  • @Where.GreaterThanOrEqual("TimeZoneCode", "x").GetRows("dsUsers");
    • Resulting filter: [TimeZoneCode] <= @parameter
  • @Where.LessThan("TimeZoneCode", "x").GetRows("dsUsers");
    • Resulting filter: [TimeZoneCode] > @parameter
  • @Where.LessThanOrEqual("TimeZoneCode", "x").GetRows("dsUsers");
    • Resulting filter: [TimeZoneCode] >= @parameter

List comparisons

  • @Where.IsEitherChar("Category", "x").GetRows("dsUsers"); - Assuming the parameter x is "abcdef":
    • Resulting filter: [Category] IN ('a','b','c','d','e','f')
  • @Where.IsInList("Category", "x").GetRows("dsUsers"); - Assuming the parameter x is "abc,xyz":
    • Resulting filter: [Category] IN ('abc','xyz')

Using query string for a "drill down" filter

  • Use the C# ternary operator (nested if necessary):
    • @{
      // Example:
      var data =
          QueryString.ContainsIntegers("c", "r") ?
              Where.IsEqual("CountryID", "c").IsEqual("RegionID", "r").GetRows("dsDepartments") :
          QueryString.ContainsInteger("c") ?
              Where.IsEqual("CountryID", "c").GetRows("dsDepartments") : GetRows("dsDepartments");
      }
      

Form values

  • Access to form values is not provided!