Sample Application

The sample application is available in the Beta 0.6.0.0 release of Lattis. It's a very simple application and is far away from being a real project. However, it demonstrates the principles of using Lattis framework.

Lattis is inspired in Struts, a very successfull Java framework for building Web applications. Those who have worked with Struts don't even need to take a look at this brief explanation, just donwload the sample application and start taking a look at the source. The similarities to Struts can be easily observed.

Microsoft .NET framewok has both a nice object model and a powerful event handling structure. Thus, when using Lattis, the final result is something very close to what the JSF (Java Server Faces) technology proposes. Developers who has also worked with JSF shouldn't have any problems understanding Lattis philosophy neither.

If you have not worked with Struts or JSF, it doesn't matter, it will still be very easy to learn how to use Lattis. Download the sample application from SourceForge and let's try to undesrtand it.

A very important piece of Lattis is a user created configuration file called Application.config. This file should be located at the application's root directory. We will first examine the Actions-Config element in Application.config. This element may have inner elements called Action-Config, which represent the actions that should be taken when a request identified by its Path attribute hits the web server. You also need to configure what class is reponsible for handling the specified action, it's done using the attribute Class. Naturally, as we're working in the .NET enviroment, you can't forget to tell Application.config the assembly name where your classes are located, that's the reason of the Assembly attribute.

The action class specified to handle the request must inherit either from Lattis.Control.Action or Lattis.Control.LookupAction. If the class inherits from Lattis.Control.Action it must override its Execute() method to determine the desired behaviour. On the other hand, if the class inherits from Lattis.Control.LookupAction, it must have a method with the same name of a value kept under a query string key used to reach this action. The key under you should place the name of the method to be invoked is specified by the MethodKey attribute of the Action-Config element. Naturally, this method, as the Execute() method in the other case, is responsible for your business logic. Take a look in Application.config file of the sample application and you'll see examples of the two approaches mentioned above. Just to make sure, I'm placing them right here.

...
    <!-- Typical and simple Action configuration. -->		
    <Action-Config
        Path="ActionDoMyStuff1.aspx"
        Class="LattisSampleApp.Actions.ActionDoMyStuff1"
        Assembly="LattisSampleApp">			
        ...
        ...
        ...				
    </Action-Config>
		
    <!-- Typical LookupAction configuration. -->
    <Action-Config
		    Path="ActionDoMyStuff2.aspx"
        Class="LattisSampleApp.Actions.ActionDoMyStuff2"
        Assembly="LattisSampleApp"
        MethodKey="op">			
        ...
        ...
        ...   			
    </Action-Config>
...

Inside Action-Config element is possible to configure two other elements. They're Forwards-Config, which keeps Forward-Config inner elements and Exceptions-Config, which keeps Exception-Config inner elements. We'll take a look at them later. First let's examine a little of the action classes.

As mentioned earlier, the action classes are responsible for handling the business logic of the request. This can be accessing façades, legacy systems, persistence mechanisms, etc. It's important to note though that these classes must inherit from either Lattis.Control.Action or Lattis.Control.LookupAction. If an action class inherits from Lattis.Control.Action, it must override its execute method and would look something like class ActionDoMyStuff1 from the sample application.
...
  public class ActionDoMyStuff1: Lattis.Control.Action
  {
    override protected ActionForward Execute(HttpContext context)
    {
      try
      {
          // do the job here...
            
          return this.FindForward("Success");

      }
      catch(Exception)
      {
          // do logging or anyother thing.
      }

      // if it gets here, something went wrong, so return failure.
      return this.FindForward("Failure"); 
    }
  }  
...
When an action class extends Lattis.Control.LookupAction it doesn't need to override its Execute() method, actually, it shouldn't do so. Extending Lattis.Control.LookupAction means that that you could place how many methods you'd want in the action class and the decision of which method should be invoked will be based on a query string parameter. The query string parameter must have the same name you specified for the attribute MethodKey in the action configuration element. Class ActionDoMyStuff2 from the sample application extends from Lattis.Control.LookupAction. Here's a snippet.
...
  public class ActionDoMyStuff2: LookupAction
  {
    protected ActionForward Method_A(HttpContext context)
    {
      string inputData = context.Request.Form["TextBox1"];
			
      // do some job using input data.
			
      return this.FindForward("Method_A_Success");
    }

    protected ActionForward Method_B(HttpContext context)
    {
      return this.FindForward("Global");
    }
  }
...
There's still another rule that action classes must follow: They always have to return an Lattis.Control.ActionForward instance. This can be achieved by using the FindForward() method present in Lattis.Control.Action. That's exactly where we come back to Application.config file and identify all the Forward-Config elements. Forward-Config tell the framework information about the destiny of the request. Usually, you'd have two diferent destinies for a request, one to be called when something goes wrong and the other one to be called when a successful operation has happened.

FindForward() method expects one parameter which is the name of the Forward-Config element to be used by this request. Naturally, the name of the Forward-Config is specified by the attribute Name and the path related to this name is specified by the attribute Path. Optionally, you can also tell the framework if the request should be redirected or just transfered to the configured path. This can be done using the Redirect attribute - default behaviour is a transfer.

When an action class uses the FindForward() method to determine the request's destiny, Lattis will first look if there's a local Forward-Config element with the name passed to the method. If it doesn't find a Forward-Config with this name, it will search global Forward-Config elements. The same behaviour is used with Exception-Config elements.

Exception-Config elements must be configured with at least two attributes: An exception class and a path. This information is represented respectively by the attributes Class and Path. Basically, here's what you need to learn about Exception-Config. If any exception is raised during the execution of your action class, Lattis will search all local and global Exception-Config elements in Application.config to verify if there's a map for the exception type that has been raised. If it finds any, the request will be transferred to the path specified in Exception-Config element. If it doesn't find a match for the exception, it's just propagated as usual.

Now that you have a better idea of how Lattis works, it'll be pretty easy to understand the sample application and adapt your projects to this paradigm (if you liked it, of course). I'm planning on developing other features for Lattis, like a nice validation structure (I'm not very happy with .NET's default one) and a page template system. Also, I'd like to work a little more on the documentation and in a sample application a bit closer to reality. Naturally, if you have doubts, questions and opinions, feel free to post it in Lattis Forum or Mailing List.