Definition

In Chameleon, views are defined in chameleon.Views table.

Structure of this table is as follows:

Column Type Description
name nvarchar(200) view name. It should be a value by which the view can be uniquely accessed.
content nvarchar(max) content of the view.
compiledContent nvarchar(max) compiled content of the view. It is used as a cache in order to prevent unnecessary compile and enhance performance.
isCompiled bit It shows whether the view is already compiled or not.

When defining a view, the only required thing is its content and giving it a unique name. compiledContent and isCompiled are system fields used by chameleon.RenderView when rendering/executing the view. This is explained later.

Compilation

Views are needed to be compiled in order to be rendered. This is done by View Engines. Chameleon uses a view engine named Gila (pronounced Hila) by default. It is also possible to create custom view engines and set them as default.

View engines are defined as UDF function. The name of Gila view-engine function is chameleon.GilaCompile. Here is its signature.

      CREATE or ALTER FUNCTION [chm].[GilaCompile]
(
    @context_id  INT            NULL,
    @viewName    NVARCHAR (200) NULL,
    @viewContent NVARCHAR (MAX) NULL
)
RETURNS NVARCHAR (MAX)
    
  • @context_id: unique context id of current web request. It enables developer to access details of current request or response (url, headers, cookies, route values, etc.). If we don't want to access any context tables, e.g. we are calling the UDF manually, we can pass an arbitrary value like 0.
  • @viewName : unique name of the view. It is used to distinguish view sections when templates are used. If there is only one view, we can pass null or an empty string.
  • @viewContent: content of the view.

Example:

      declare @view nvarchar(max)
declare @compiledView nvarchar(max)

set @view = N'
<%
    declare @name varchar(30)

    set @name = ''Chameleon!''
%>
<h1>Welcome to <%=@name%></h1>
'

set @compiledView = chm.GilaCompile(0, '', @view)
    

The above code, generates the following T-SQL code for the view.

      set @__result = ''

    declare @name varchar(30)

    set @name = 'Chameleon!'

set @__result = @__result + N'
<h1>Welcome to '
set @__result = @__result + chm.HtmlEncode(@name)
set @__result = @__result + N'</h1>
'
    

As it is seen, the generated code is set to @compiledView variable. So, it can be easily executed using sp_executesql. This is explained in next section.

Execution

After compiling a view, its compiled content can be executed using sp_executesql system stored procedure. When Gila view engine compiles a view, it uses an output variable named @__result in the compiled code to store the generated content. Thus, when calling sp_executesdql, we should define such parameter for the compiled code. The variable we specify for that will hold the resulting content after sp_executesql is finished executing.

      declare @result nvarchar(max)

exec sp_executesql @compiledView, N'@__result nvarchar(max) out', @__result = @result out

print @result
    

Here is the final output of executing the compiled view:

      <h1>Welcome to Chameleon!</h1>

    

There could also be a @model input parameter for a view by which we can pass some data to a view. Examples of parametric views is described in Gila's documentation.

Rendering

In Chameleon, rendering a view is performed by a stored procedure named chameleon.RenderView.

      CREATE or ALTER PROCEDURE [chameleon].[RenderView]
(
	@context_id	int,
	@name		nvarchar(100),
	@model		nvarchar(max),
	@result		nvarchar(max) out
)
    
  • @context_id: context_id of the current web request.
  • @name: view name in chameleon.Views table.
  • @model: custom model that should be passed to view when it is executed.
  • @result: final output

chameleon.RenderView checks first if the view is already compiled or not using the isCompiled field. If it is not compiled, it tries to compile the view using the view-engine that is set for Chameleon framework (Gila view-engine by default). If compilation is successful, it then stores compiled content into compiledContent field for the given view, so that it does not need to re-compile the view next time. Next, it executes the compiled content using sp_executesql as it was described in previous section.

By default, isCompiled is 0 (false) for any view that is inserted into chameleon.Views table. After chameleon.RenderView renders (and thus compiles) a view, it sets this column to 1 (true) for the view. if the view content is updated, the isCompiled flag is set back to 0 again, so that in next RenderView invocation, correct output is returned back to the user not the old stale content. This is done by an update trigger named [chameleon].[Views_Update] that clears isCompiled field for updated records whenever content of any record is changed.

      -- After execution of the following UPDATE command, [chameleon].[Views_Update] is triggered
-- and [isCompiled] will be set to 0 for 'my-view' record.

update chameleon.Views set [content] = N'...' where [name] = 'my-view'
    

It is also possible to manually reset isCompiled so that the view is compiled explicitly on next render.

      update chameleon.Views set [isCompiled] = 0 where [name] = 'my-view'
    

Custom View Engine

All view engines should be defined as UDF functions in order to be invocable by chameleon.RenderView. Name of all view-engine UDF functions should end in Compile and their signature should follow the following signature.

		  CREATE or ALTER FUNCTION MyViewEngineCompile
(
	@context_id  INT            NULL,
	@viewName    NVARCHAR (200) NULL,
	@viewContent NVARCHAR (MAX) NULL
)
RETURNS NVARCHAR (MAX)
		

As it is seen, view-engine compile function should have three parameters @context_id, viewName and viewContext of int, nvarchar(200) and nvarchar(max) data type respectively and should return nvarchar(max). The function could be defined in any schema. It is developer's choice. GilaCompiled is defined in chm schema.

A view-engine compile function could be implemented as a pure T-SQL UDF or a SQL-CLR UDF. Gila itself is implemented as a SQL-CLR UDF and is added to database when Chameleon framework is installed.

chm.GilaCompile function internally uses GilaViewEngine class in Chameleon.Core library. Definition of Chamelelon view-engines is described in Chameleon.Core's IChameleonViewEngine interface.

It is not necessary that a SQL-CLR view-engine should implement IChameleonViewEngine interface. The only thing that is necessary is that the resulting function follows the signature described in a few paragraphs above.