Castle Igloo

Castle Igloo (ppt) is a very interesting experiment in bringing more MVC goodness into the WebForms. I have to say that when I dove into the code, the ideas that Gilles Bayon (no blog :-( ) had there blew my mind away. I always believed that trying to do MVC in ASP.Net was possible, but fairly awkward.

My main issue with this was always that I always had to do extra work in both the view and the controller in order to make this work, and I never felt that I really got the flexibility that I can get in MonoRail. Here is an implementation of MVP from Phil Haack, as an example. The problem here is that I still have the following problems:

  • I need to define an interface for the view, which will likely contains a lot of data passing parameters.
  • My controller is dependant of that interface, if I want to test that, I need to mock/fake the interface before I can use it, not a big deal, but not as trivial as just dowing new MyController() in the test.
  • My view implementation is dependant on the controller, and is actually responsible for creating it.

I may be spoiled by the pure MVC that I can get in MonoRail, but I really want that back. As I said, I didn't believe that I could get nearly the same experiance, but Gilles has proven me wrong. [Forehead still hurting from that smack]. You can get the code here, I suggest taking a look and seeing what is in there.

Here is a small part of the controller:

public class PatientController : BaseController

{

 

    [Inject(Name = "doctor")]

    public Doctor Doctor

    {

        set { _doctor = value; }

    }

 

    [Inject]

    public IList<Patient> Patients

    {

        set { _patients = value; }

    }

}

And another small part of the view the view:

public partial class Index : Page

{

    [Inject]

    public IList<Patient> Patients

    {

        set { _patients = value; }

    }

}

Notice that the controller doesn't care about the view at all. How does it works? Well, there is some magic behind the scenes, but basically, the controller can register an object in a registry, and when it is done, that object is populated to the view transperantly. Here is the method on the controller that gets the list of patients.

public virtual IList<Patient> RetrievePatients()

{

    IList<Patient> patients = _patientService.RetrievePatients(Doctor);

 

    Scope["Patients"] = patients;

 

    return patients;

}

The view can either call this directly, or rely on getting the value from the scope:

protected void Page_Load(object sender, EventArgs e)

{

     if (!IsPostBack)

     {

            GridViewBlog.DataSource = PatientController.RetrievePatients();

            GridViewBlog.DataBind();

     }

     else

     {

            GridViewBlog.DataSource = Patients;

            GridViewBlog.DataBind();

     }

}

In the second case, we got the value from the scope automatically.

What we gained:

  • No need to define an interface for the view.
  • Controller completely seperated from the view, easier testability.
  • The view is still tied to the controller (since it needs to let it know about things such as button clicks, etc), but trying to avoid that is something that isn't really possible with WebForms (but you are welcome to prove me wrong).
  • Strongly typed support for passing items from controller to view :-)

I fear that I am not really doing much justice to Igloo, mainly because I am still in the process of grokking it. There are still several things there that I need to figure out. There is an automatic navigation part that I am doubtful about (I don't see the usecase, actually). I think that I will try and get a small sample with just the bijection support (the automatic injection and outjection of properties from both controller and view), just to see how I can make this work.

Print | posted on Friday, January 26, 2007 3:47 PM

Feedback


Gravatar

#  1/26/2007 6:06 PM Stuart Carnie

I think the decoupling of events / actions / commands can be achieved by using something similar to CABs EventBroker and command handlers.

In your controller, you can decorate your command method

[EventSubscriber(&quot;evt://patient/commit&quot;)]
public void CommitPatient(object sender, Patient patient)
{

}

in the web form code, the commit patient button click (or some more declarative approach) would raise the command:

void CommitButton_OnClick()
{
if (CommitPatient != null)
CommitPatient(null, CurrentPatient);
}

[EventPublication(&quot;evt://patient/commit&quot;)
public event EventHandler&lt;Patient&gt; CommitPatient;

Thoughts?


Gravatar

#  1/26/2007 7:19 PM hammett

I haven't checked this experiment yet, but your post just ring the &quot;too much magic&quot; bell.


Gravatar

#  1/26/2007 7:48 PM Stuart Carnie

Are you directing that towards me, Hammett?


Gravatar

#  1/26/2007 8:02 PM Ayende Rahien

I don't think that I agree with this.
The main benefit that I see is that you can put stuff in the scope and have it automatically transfered to the view.
This is something that I can have in an untyped way, but having it just happening automatically is really cool.

You can think about this as an extension for:
//controller:
Scope[&quot;doctor&quot;] = new Doctor();

//view
public Doctor Doctor
{
get { return (Doctor)Scope[&quot;doctor&quot;]; }
}
Just this is a great way to handle the separation of the controller from the view. The rest is just icing on the cake.
I may adopt just the Scope idea alone, since that is far easier to explain, but the Bijection support is really cool to watch.


Gravatar

#  1/26/2007 8:11 PM Ayende Rahien

@stuart,
I think that I like the separation, but I am not sure how I would handle the state change in this case.
The problem is something like:

void Login_Click()
{
RaiseLoginRequest(user,pass);
if ( ??? )
{
ShowSuccessulLogin();
}
}


Gravatar

#  1/26/2007 8:25 PM hammett

You don't need to agree with me. That was a first impression. Might be proven wrong after I sit and dig in... or not.

As I mentioned, I haven't even glanced at the code, just read your post.


Gravatar

#  1/26/2007 8:48 PM Stuart Carnie

CAB handles state through the WorkItem.State[] dictionary. The key in the State dictionary is again well known, and ideally would be constants defined in a static class, to avoid typo's.

This WorkItem is available to both the publisher and subscriber, either through a service or dependency injection.

The subscriber to the RaiseLoginRequest command would set the state appropriately, and then the Login_Click() method can:

if (WorkItem.State[StateConstants.LOGIN_STATE] == ....)
{
ShowSuccessfulLogin();
}

WorkItem is hierarchical, so you can search up the WorkItem tree to find the right state. That is, WorkItem.ParentWorkItem (is either null or another instance derived from WorkItem).


Gravatar

#  1/26/2007 9:08 PM Liang

There have another two (at least, maybe) MVP framework using Castle. Have you ever taken look at?

Bill Pierce
http://blogs.meetandplay.com/WPierce/archive/2006/12/24/Revisited_MVP_Framework.aspx

Bernardo Heynemann
http://www.codeplex.com/nmvp


Gravatar

#  1/27/2007 1:10 AM Samir

Very cool.
I like it.


Gravatar

#  1/28/2007 10:34 PM Jonathan Allen

&gt; The problem here is that I still have the following problems:
&gt; My controller is dependant of that interface, if I want to test that, I need to mock/fake the interface before I can use it, not a big deal, but not as trivial as just dowing new MyController() in the test.
&gt; My view implementation is dependant on the controller, and is actually responsible for creating it.

I don't understand why you think you have a problem. Consider these passaged from the original definition of the MVC pattern:

&quot;Communication between a view and its associated controller is straightforward because View and Controller are specifically designed to work together. Models, on the other hand, communicate in a more subtle manner.&quot;

&quot;Unlike the model, which may be loosely connected to multiple MVC triads, Each view is associated with a unique controller and vice versa. Instance variables in each maintain this tight coupling.&quot;

-- Applications Programming in Smalltalk-80(TM): How to use Model-View-Controller (MVC) http://st-www.cs.uiuc.edu/users/smarch/st-docs/mvc.html

Notice how it explicitly says that there will be a tight coupling between the view and controller.

While your view of MVC is shared by many, I have a hard time reconciling it with the original definition. They are not just variants; they are on literally opposite positions in regards to coupling.

I would like to hear your position on exactly what the MVC pattern is. And if it does in fact differ from the original definition, the reasons why you think the 'new' definition is better.


Gravatar

# re: Castle Igloo 2/3/2007 10:00 PM Ayende Rahien

My response:
http://www.ayende.com/Blog/archive/2007/02/03/Why-seperating-the-View--Controller-is-important.aspx


Gravatar

# re: Castle Igloo 2/8/2007 7:59 AM S

I could not get the code to build


Gravatar

# re: Castle Igloo 2/8/2007 8:01 AM Ayende Rahien

Please post a question on the caslte-dev group, about it.


Gravatar

# re: Castle Igloo 3/1/2007 1:48 PM sternr

I don't like the Igloo's injection approach,
I think object injection should not be implemented as properties but as method parameters.
Every controller is a set of services (methods), and by their nature some method require different properties, but each has the ones he must accept in order to operate.
What I'm trying to say is, that you cant know on each call which properties are assigned and which aren't - the assignment is not explicit enough...
Just my 2 lira's...

--sternr


Gravatar

# re: Castle Igloo 3/17/2007 10:47 PM Jeff Brown

How about code generation?

There's still too much boilerplate in here that could be omitted without any confusion. If you can hook ASP.Net so that code-behind can be written in Iron Python then it should be possible to make it use other dynamic classes. Basically make the Page be abstract and then dynamically derive and fill in the blanks.

I like Stuart's event publisher/subscriber suggestion too. It keeps the controller in the loop. The forwarding hooks to the controller could probably be implemented generatively.

Comments have been closed on this topic.