Igloo: Model View Controller In ASP.Net
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
{
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.
Comments
Do you have an update on where the Igloo repository exists? I can't seem to find anything on the SVN repo that you've linked in your previous post on it.
Could you show me what that 'Repository' could looks like?
I'm working on a Monorail project and I like the idea of making requests through this layer as you have it there with the repository
It is on the experiment branch of castle SVN
Experiments\Castle.Igloo
Hi Ayende
I have had the same idea of you for the Scope.Input[] but I have imagined put them on the NavigationState.Params[] or added some properties like those on the controller
[Param[Constants.Policy.Templates.SavedTemplateId]]
public string maybeId = string.Empty;
[Param[Constants.Policy.Templates.SavedTemplateName]]
public string newName = string.Empty;
Gilles
I cannot find any Igloo sources in SVN Repository...
Are you planning to post any sample of using Igloo + Repository<T>
Thanks
Castle's SVN is under some maintenance, so please be patient.
I like the separation, but how would you handle WebForms controls within a nested naming container (ie. "ctl_0_Name")
@Doug,
I am using a custom version of Igloo, which had a lot of stuff stripped out.
The SVN should be back online in a few days.
@Steve,
You can read about Repository<T> here:
http://www.ayende.com/Blog/archive/2006/12/24/7003.aspx
The implementation itself is here:
http://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-commons/Rhino.Commons/Repositories/ARRepository.cs
@Gilles,
I am a bit worried of adding the bijection into the application. The issue here is two fold:
A) I am getting a bit "Too Much Magic" vibe when I think about it. It is cool and I like the idea, but I have hard time trying to explain it as it is.
B) Because we can't do injection of parameters, it would mean that the controller would have to have several properties that are meant solely for input. And since a lot of methods needs different parameters, it would mean large number of fields/properties that are mostly empty, and no easy way to associate between what I need in a method to its fields without reading everything.
This approach is a bit K&R C, but it make it clear what I am using in a given method.
@Hammett,
The nested name part is taken care of by the Input[...] method.
I name I am passing is something like "SavedTemplateNewName", the Input them searches for everything that EndsWith SavedTemplateNewName, so I can get the nested names support without bothering to think about it.
The only thing that I need to worry about it not to have conflicting ID names, which is something that I do at any rate.
Comment preview