Eiffel ASP. NET Web pages

 

This chapter covers enough information on ASP. NET for Eiffel developers to be able to write ASP pages using the Eiffel language.

However, this chapter will not explain how to write sophisticated ASP web pages, because it would require an entire book! We will mostly explain the specificities of a page written in Eiffel, going through simple examples.

 

Getting started

Render blocs <% %>

Inheritance

Web services

Data binding

Limitations

Examples

 

 

Getting started

To write an ASP. NET page in the Eiffel language, you do not have any particular installation or configuration operation to do. You simply have to specify in the header of your ASP page that you use Eiffel language.

<%@ Page Language="Eiffel" %>

That is all you need to do!

 

However, to be able to navigate into your Eiffel ASP pages, as all other any .NET language require, you need to place your ASP files in directory shared as a Web Application through the IIS Manager snap-in.

 

Using <% %> render blocks in an Eiffel ASP. NET Web page

ASP. NET supports the syntax <% %> code render blocks that can be intermixed with HTML content within an .aspx file. These code blocks execute in a top-down manner at page render time. So you can insert inline expression in your html code.

	<% response.write_object (3 + 2) %>
	<% response.write_string (("Hello world!").to_cil) %>

Here, in the html code, we call an inline expression to write the integer "3" and to write the string "Hello world!". response is an attribute of the inherited class WEB_WEB_PAGE that allows to write dynamically text in the page. But a more common use of this attribute is implicit, using the following shortcut syntax:

	<%=3 + 2 %>
	<%="Hello world!" %>

The result of both syntaxes is the same.

You have probably noticed the call to the feature to_cil to display a string. This feature converts the Eiffel string (STRING) "Hello world!" into a .NET string (SYSTEM_STRING) that ASP. NET uses.

Caution: Do not forget to add the feature to_cil when you need to write a string, otherwise you will have a compilation error.

 

The render blocks are pretty useless to dynamism a Web page without the use of some variables. So you will probably need to declare some variables in your code, either to make some loop or to have an temporary value.

 

To declare a variable to be used in a render bloc, you need to create a separated render bloc started with the keyword local. The variables declaration follows the usual Eiffel declarations syntax rules.

<% local
	i, j: INTEGER;
	array: ARRAY [STRING] %>

You may then use the variables in the following render blocks:

<% array := <<"Hello world", "This is an eiffel ASP.NET example", "using local variables">>
    from i := 1
    until i = 4
    loop %>
	<% j := i * i %>
	<font size="<%= j %>"> <%=(array.item (i)).to_cil%> </font>
<%   i := i + 1
     end  %>

Caution: Be aware that local or global variables must have a name that is unique throughout the Web page. For example you may not have a local variable called on_load, because this is already the name of a feature inherited from WEB_WEB_PAGE! It will result a compilation error.

 

Inheritance

All ASP. NET pages inherit the external class WEB_PAGE. All of your controls, presentation information, and logic are used to extend this class to provide you with an object that supports the functionality of the page you created. As you can use all the features contained in the class WEB_PAGE, you can also add inheritance clauses in your ASP. NET page to modify the properties of these inherited features. You can rename, undefine and redefine inherited features using the same syntax than in an Eiffel class.

To do this, you have to include in your ASP. NET page a separate script where you will only specify witch feature you want to rename, undefine or redefine.

Here is an example:

	<script runat="server">
	    inherit
 	       WEB_PAGE
	            rename
	                on_load as my_on_load
	            undefine
	                to_string
	            redefine
	                my_on_load
	            end
	</script>

Here, like in all ASP. NET pages, all features of class WEB_PAGE are inherited; but the feature on_load is renamed as my_on_load, the feature to_string is undefined and finally the feature my_on_load is redefined. This means that in your ASP. NET page, if you want to make an explicit call to the feature on_load you must do it with its new name my_on_load. In addition, you cannot call the feature to_string anymore because it is undefined.

 

Code behind

The code behind mechanism allow the developer to separate the code from the actual content of the page. 

The principle of code is that you create a class for your code, and inherit this class from the ASP. NET Page object. This gives your class access to the page intrinsic, and allows it to interact with the postback architecture. You then create the ASP. NET page and use a page directive to inherit from the created class.

Your code behind class has to inherit WEB_PAGE (System.UI.Web.Page) and ANY. Then, within your class, you should declare public instances (export {ANY}) of ASP. NET server controls that are on the web page, using the same name for the variables that the Web Control has.

Warning: You cannot use code behind written in Eiffel within an ASP. NET Eiffel page. See the Eiffel restrictions.

 

Web services and Eiffel

ASP. NET provides support for Web Services with the .asmx file. An .asmx file is a text file that is similar to an .aspx file. These files can be part of an ASP. NET application that includes .aspx files. These files are then URI-addressable, just as .aspx files are.

Here is a very simple Eiffel Web Service:

<%@ WebService class="HELLO_WORLD" Language="Eiffel" %>

class
    HELLO_WORLD

inherit
    WEB_WEB_SERVICE
	undefine
	    finalize, get_hash_code, equals, to_string
	end
    ANY

feature -- Basic operation

    say_hello_world: SYSTEM_STRING is
	    -- Return the "Hello world!" string.
	indexing
	    attribute: create {WEB_WEB_METHOD_ATTRIBUTE}.make [["description", ("Returns the %"Hello world!%" string.").to_cil]] end
	do
	    Result := ("Hello world!").to_cil
	end

end -- class HELLO_WORLD

This .asmx file declares the class HELLO_WORLD that inherits the classes WEB_WEB_SERVICE and ANY. Note that you must inherit the class ANY, while the inheritance of WEB_SERVICE is optional but strongly recommended as it gives access to some really useful features. Finally, any methods that will be accessible as part of the service have the custom attribute create {WEB_WEB_METHOD_ATTRIBUTE}.make in their indexing clause.

Caution: Your web service accessible methods can not return an Eiffel string (STRING). You must use the .NET string version (SYSTEM_STRING).

 

 

Cast and Data binding

ASP. NET introduces a new declarative data binding syntax. This extremely flexible syntax permits the developer to bind not only to data sources, but also to simple properties, collections, expressions, and even results returned from methods calls.

However, this syntax allows to bind data only by writing an expression. The problem we can encounter in Eiffel, is when we want to bind a data that need to be cast in order to be bind. The solution to this problem is to use a function that will operate the "cast" and return its result. Here is an example:

<html>
<script language="Eiffel" runat="server">
	...
    data_item (container: WEB_DATA_LIST_ITEM): DICTIONARY_ENTRY is
	    -- Retrieve container.data_item.
	require
	    non_void_container: container /= Void
	do
	    Result ?= container.data_item
	ensure
	    non_void_result: Result /= Void
	end
</script>

<body>
   <form runat=server>
	<asp:DataList id="my_data_list" runat="server">
	    <ItemTemplate>
		<%# (data_item (container)).key %> :
		<%# (data_item (container)).value %>
	    </ItemTemplate>

	</asp:DataList>
    </form>

</body>
<html>

The problem previously highlighted is, in this example, that in order to bind the key and the value associated to the DataList, we need to cast container.data_item. To realize this operation, we simply added the function data_item, that take a WEB_DATA_LIST_ITEM (corresponding to the .NET type DataList) and that return a DICTIONARY_ENTRY. From this result, we can retrieve the key and the value, that we can bind.

 

 

Eiffel limitations

The Eiffel ASP. NET enabler is only compatible with the .NET framework version 1.0.

 

Within an ASP. NET page written in Eiffel, it is not possible to write any code behind also written in Eiffel.

However, you can use the code behind mechanism using Eiffel code as long as the Eiffel code is referenced from a page not written in Eiffel.

You can also use some code behind within an ASP. NET page written in Eiffel as long as the code behind is not written in Eiffel.

<%@ Page Language="C#" inherits="CLASS_NAME" Src="Eiffel class path" %>			<!-- supported -->
<%@ Page Language="Eiffel" inherits="CLASS_NAME" Src=".NET class path" %>			<!-- supported -->
<%@ Page Language="Eiffel" inherits="CLASS_NAME" Src="Eiffel class path" %>		<!-- not supported -->

Note: If you want to write your code in Eiffel using an Eiffel page, you have to write your entire Eiffel code inside your Eiffel page.

 

A predefine list of referenced assemblies is passed to the compiler for all Eiffel page compilation. You cannot change it, or redefine their prefix. For example the .NET class System.UI.Web.Page is the class PAGE prefixed with WEB_, ie WEB_PAGE. Here is the complete list of referenced assemblies:

Assembly Prefix
mscorlib.dll  
System.dll SYSTEM_DLL_
System.Xml XML_
System.Data.dll DATA_
System.Web.dll WEB_
System.Web.Services.dll WEB_
System.Drawing.dll DRAWING_
System.EnterpriseServices.dll  

You cannot refer an Eiffel assembly from a page written in Eiffel:

<%@ Assembly Name="my_non_eiffel_assembly" %>		<!-- supported -->
<%@ Assembly Name="my_eiffel_assembly" %> 		<!-- not supported -->

 

ASP. NET Eiffel samples

This set of examples shows you all the possibilities you can exploit using Eiffel in an ASP. NET application.