Here is my solution for the problem explained in the
previous
post.
So the problem was, how can you reuse views (aspx pages) in different
controllers (processes, pageflows, ... whatever you want to call them)?
I'm still using the standard Model-View-Presenter-Controller pattern used by
WCSF but I'm abstracting the controller part from the presenter and I'll be
passing the view (through it's interface) to the controller.
ICanHandleView<TView>
For every view the controller can handle the controller will implement an
interface
ICanHandleView<TView>. This generic interface has
two methods,
HandleView(TView view) and
FillView(TView
view). FillView will be mostly called when the page is loaded to fill
the view with state information and HandleView will be called when an action
occurred (e.g. a button click). In the implementation of HandleView you take
the data from the view, store it in the controller and then decide to which
page you will redirect the user. So basically the Presenter is just there to
translate actions of the UI into calls to the controller.
BasePresenter
When you add a page with WCSF it will also generate a presenter that inherits
from
Presenter<T> where T is the interface of your view.
I've created a class
BasePresenter that inherits from
Presenter<T>.
BasePresenter has a property
Controller that returns a
ICanHandle(TView), behind
the scenes this property uses a static class
ControllerFactory
that creates a new controller or correlates the current request to an existing
controller. So, when WCSF created your presenter you just change the
Presenter<T> it inherits from with
BasePresenter<T>.
ControllerFactory
This little workhorse is responsible to do the correlation between a request
and a new or existing controller. Actually
ControllerFactory is
just a static class that will instantiate the real factory, in my case
WebControllerFactory. This was done to abstract the asp.net
infrastructure from the rest of the system as the
WebControllerFactory will use the
HttpContext to do
the correlation.
I hope I can make this all a bit clearer with the following class
diagram:
(click to enlarge)
Correlation
The correlation strategy of my
WebControllerFactory is the
following:
(click to enlarge)
red dots: flow when the first page of the process is first
requested
green dots: flow when the first page of the process is postbacked
blue dots: flow of all the following pages in the process
The reason I use the hidden field is to avoid that on a postback, of the first
page of the process, a new controller would be created.
Some technical details:
When a controller is redirecting to the next page it should add the "flowid"
parameter to the url. To get to the page object of a request, to add or read
the hidden field value, I use HttpContext.Current.CurrentHandler, this is a
IHttpHandler that can be cassed to a System.Web.UI.Page. To instantiate the
correct controller factory and controllers I used Unity, the details of this I
leave as an exercise to you the reader.
All of this might seem a bit complicated but once this is implemented it's
really easy to use:
- generate your pages and presenters with WCSF
- write the code of your controller, unfortunately you still have to do this
yourself
- configure unity
- change the base class of the presenter to BasePresenter<...>
and it's ready!
If something is not clear or if you would have a better way to do this please
let me know.