Controllers

Controllers are used to handle URLs in a predefined way. The URL are splitted up into parts on each slash. For example: "/user/edit/1" says that we should invoke the method "edit" in UserController (may also be called just User). "1" are put in a property called Id.

The following controller would handle the above mentioned URL:

public class UserController : RequestController
{
  public string Edit()
  {
    return "Ohh, you wanted to edit " + Id + "?";
  }
}


That's all code needed to handle that url.

Send binary

Returning a string works great for most of the time, but sometimes you need to send a file or stream something.
You can do this by tagging a method with the RawHandler attribute, which tells the controller module to add a method not returning anything.

public class UserController : RequestController
{
  \[RawHandler\]
  public string File()
  {
    Response.ContentType = "application/octet-stream";
    // pseudo code
    Response.ContentLength = File.Size("mypath" + Id);
    file = File.Open("mypath" + Id);
    byte[] buffer = new byte[8192];
    while (file.read(buffer))
      Response.SendBody(buffer, 0, 8192);
  }
}

Streaming

Streaming is not 100% done, it requires the use of chucked encoding.

Before filters

Before filters are invoked before each handler method. They can be used to do any additional processing or just determine if the handler method should be invoked at all. They are therefore perfect to determine if a user have been logged in or not.

Example 1: Class filter

public class UserController : RequestController
{
  TemplateManager _mgr;

  public UserController(TemplateManager mgr)
  {
    _mgr = mgr;
  }

  public string Login()
  {
    return _mgr.Render("public\\views\\user\\login.haml", "username", string.Empty);
  }

  // called by login form
  public string DoLogin()
  {
    //Using my favorite ORM Layer (coded by me ;)) Can be found on www.assembla.com in project Tiny Library
    User usr = Program.DataManager.Fetch<User>(new string[] {"UserName = ? AND Password = ?", Request.Form["user"]["name"].Value, Request.Form["user"]["password"].Value});
    if (usr == null)
      return _mgr.Render("public\\views\\user\\login.haml", "username", Request.Form["user"]["name"].Value);

    Session["user"] = usr;
    Response.Redirect("/user/index/");
    return null;
  }

  // All non logged in users will be redirected to login page thanks to the before filter.
  public string Index()
  {
    _mgr.Render("public\\views\\user\\index.haml", "user", Session["user"]);
  }

  [[BeforeFilter("ValidateUser")]]
  protected bool ValidateLogin()
  {
    if (MethodName == "login" || MethodName == "dologin")
      return true; // should always be able to login =)

    User user = (User)Session["user"];
    if (user == null || user.Status < UserStatus.RegularUser)
    {
      Response.Redirect("/user/login/");
      return false; // should not be able to access the page.
    }

    return true;
  }
}


Normally I would put the rendering and the before filter in a base controller which all other controllers derive. In that way you will never have to think about login handling or how the rendering is done.

Last edited Apr 15, 2008 at 6:45 AM by jgauffin, version 2

Comments

loudenvier May 16, 2011 at 3:05 AM 
The ControllersSample doesn't work with version 2.0. You need to use IActionResult...

public class UserController : RequestController
{
public IActionResult Edit()
{
return new StringContent("Ohh, you wanted to edit " + Id + "?");
}
}

This should work...

For the second example, maybe BinaryContent will work...