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.
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.
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.
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.
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.
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).
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.
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 -->
This set of examples shows you all the possibilities you can exploit using Eiffel in an ASP. NET application.