Igloo: Model View Controller In ASP.Net

time to read 24 min | 4678 words

I wrote about Igloo before, but now I am writing after several weeks of using it for a big project of ours.

A bit about the architecture, we are using MVC (by utilizing Windosr + Igloo) in a way that I find very elegant. The UI layer is composed of WebForms and Atlas, and the backend is Active Record using Repository<T>. Transactions are handled by the Automatic Transaction Management facility from Windsor.

Let us think about creating a new policy, there are a lot of fields to fill, so the customer would like to have a set of templates that they can use to automatically fill most of them. The code for adding/editing the policy template is mostly boring data entry stuff, mapping from user input to the policy object (yes ,I miss MonoRail databinding dearly).

Here is the controller code that is responsible for renaming a template:

[Transactional]

public class NewPolicyController : BaseController

{

       [Transaction]

       public virtual bool RenameSavedPolicyTemplate()

       {

              string newName = Scope.Input[Constants.Policy.Templates.SavedTemplateName];

              string maybeId = Scope.Input[Constants.Policy.Templates.SavedTemplateId];

              int id;

              if (string.IsNullOrEmpty(newName))

              {

                     Scope.ErrorMessage = Resources.CannotRenameTemplateToEmptyName;

                     return false;

              }

              if(int.TryParse(maybeId, out id)==false)

              {

                     Scope.ErrorMessage = string.Format(Resources.InvalidId, maybeId);

                     return false;

              }

              //Note that this also validate that the current user owns the template

              PolicyTemplate template = Repository<PolicyTemplate>.FindOne(

                     Where.PolicyTemplate.Id == id &&

                     Where.PolicyTemplate.User == CurrentUser

                     );

              if(template==null)

              {

                     Scope.ErrorMessage = Resources.TemplateNotFound;

                     return false;

              }

              bool exists = Repository<PolicyTemplate>.Exists(

                     Where.PolicyTemplate.User == CurrentUser &&

                     Where.PolicyTemplate.Name == newName

                     );

              if(exists)

              {

                     Scope.ErrorMessage = string.Format(Resources.PolicyTemplateNameAlreadyExists,

                                                        newName);

                     return false;

              }

              template.Name = newName;

              Repository<PolicyTemplate>.Save(template);

              return true;

       }

}

A couple of things to note, Scope.Input[] is a dictionary of the inputs from the user (basically resolves to Request.Form on the web, or a hashtable for the tests). This method is longer than I like, but it is very simple, so I can live with it.

Here is the code from the view (aspx page):

protected void RenameSavedTemplate_Click(object sender, EventArgs e)

{

       if(Controller.RenameSavedPolicyTemplate()==false)

       {

               SavedTemplateWarningMessage.Text = Scope.ErrorMessage;

              return;

       }

       ManageSavedTemplatesRepeater.DataSource = Controller.GetPolicyTemplates();

       DataBind();

}

Notice that in this case, I am using return values to signify success/failure. I usually frown at such things, but in this case, I successfully manage the rename, fail entirely, or get an exception. It is non of the views concern at any rate. It is handled in the controller internaly, which means that the view only need to deal with presentation logic: "What should I display if the controller couldn't rename the template?"

I have more to say about this, but I am heading off to the Israeli Blogger Dinner, so I'll probably catch up with this at a later time.