ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests to Code

asp.net, code, asp.net mvc 0 comments suggest edit

UPDATE: For a more full featured implementation of this pattern for ASP.NET Web Forms, check out the WebForms MVP project! It’s available as a NuGet package! Install-Package WebFormsMVP

Martin Fowler recently split the Model-View-Presenter pattern into two new patterns, Supervising Controller and Passive View. They are pretty much two different flavors of the MVP pattern differentiated by how much application logic is placed within the view.

The goal of this post is to demonstrate an end-to-end walk-through of the process of implementing the Supervising Controller pattern starting with a rough schematic. My goal is not explain the Supervising Controller pattern in detail but to help others take it out of the sounds nice in theory bucket and move it into I can and will use this in a real project, I promise bucket. There are many ways to implement the pattern for any given scenario, so keep in mind that this is not the one true way, just one way.

The Schematic

For this fictional scenario, I might as well pick an interface that I am familiar with, a blogging engine. In particular I will create a very very simple page to edit the body of a blog post and add and remove tags associated with the post. In trying to keep the example simple, I leave out all minor and extraneous details such as a title for the blog post. How important is a title, really?

Tag UI Schematic

The chicken scrawl above is a hand-drawn quick and dirty schematic for the user interface. No surprises here. There is a text area for entering the body of the blog post. There is a list of existing tags for the current post on the right. At the bottom of the list of tags is a text box. In order to add a new tag, the user can simply type in the name of the tag and click the add button. This will add a new tag to the list and associate it to the blog post. Note that when adding tags, any changes to the blog post should not be lost. The user can also remove tags by clicking the [x] next to the tag name.

When the user is finally ready to save the blog entry, the user clicks the Save button.

Defining the View

The next step is to analyze the schematic and define a view interface that can appropriately represent this interface. For the sake of this discussion, I will implement a single view that will represent this entire page. An alternative approach would be to break the page into two user controls and implement each user control independently with its own view and presenter.

Examining the schematic reveals what properties we need to populate the view interface. Obviously the view should have a getter and setter for the body text. Probably good to have a property that returns a collection of tags as well. We will want a getter and setter for the tag textbox, and a an event each for the buttons.

The entire process of defining a view interface may take multiple iterations. I am going to skip that long process (mainly because I cannot bear to type that much) and show you what I ended up with. Before I created the specific view interface, I defined a more generic base interface, IView. This is the base interface I will use for all my ASP.NET views.

public interface IView
{
    event EventHandler Init;

    event EventHandler Load;

    bool IsPostBack { get; }

    void DataBind();

    bool IsValid { get;}
}

One thing to notice is this interface defines two events, Init and Load. Most implementations of MVP that I’ve seen place an Initialize method on the Presenter/Controller class that every concrete view implementation must remember to call at the right time.

But when you have an ASP.NET Control or Page implement this interface, you don’t have to remember to have every concrete view call anything and you don’t have to implement these interfaces. It is already done for you by the ASP.NET runtime. You get the initialization call for free. Less code is better code I always say.

One common complaint with such an approach is that events on an interface are hard to test. I thought the same until I discovered Rhino Mocks. Now testing events is quite easy.

Here is the final view interface for the blog post edit page.

public interface IPostEditView : IView
{
    string BlogPostBody { get;set;}

    ICollection<Tag> Tags { get; set; }

    string NewTag { get; set;}

    int BlogPostId {get;}

    event EventHandler PostSaved;

    event EventHandler TagCreated;

    event EventHandler<TagRemovedEventArgs> TagRemoved;
}

Again, no surprises. One thing to note is the BlogPostId property. In this scenario, it is the view that is responsible for figuring out which blog post to edit. This makes sense in a lot of scenarios as the id may be coming in from a query string or via some other means. However, in other scenarios, you might want the controller to be responsible for figuring out which post to edit.

Writing a Unit Test

Now our next major task is to implement the presenter. But before we do that, we should start off with a basic unit test. The first thing I want to test is that the presenter properly attaches to the events on the view. The following is the test I wrote. Notice that there is some code in the SetUp method that I am not presenting here. You can see that code later.

[Test]
public void VerifyAttachesToViewEvents()
{
    viewMock.Load += null;
    LastCall.IgnoreArguments();
    viewMock.PostSaved += null;
    LastCall.IgnoreArguments();
    mocks.ReplayAll();
    new PostEditController(viewMock, 
      this.dataServiceMock);
    mocks.VerifyAll();
}

Defining the presenter {.clear}

With the test in place, I can move forward and start implementing the controller. In practice, I only implement enough to get my test to pass, at which point I write another test and the cycle continues. In order not to bore you, I will skip ahead and show you the entire Controller implementation.

public class PostEditController
{
    BlogPost blogPost;
    IPostEditView view;
    IBlogDataService dataService;
    
    //Attaches this presenter to the view’s events.
    public PostEditController(IPostEditView view, 
      IBlogDataService dataService)
    {
        this.view = view;
        this.dataService = dataService;
        SubscribeViewToEvents();
    }
    
    void SubscribeViewToEvents()
    {
        view.Load += OnViewLoad;
        view.PostSaved += OnPostSaved;
        view.TagCreated += OnTagCreated;
        view.TagRemoved += OnTagRemoved;
    }

    void OnTagRemoved(object sender, TagRemovedEventArgs e)
    {
        this.dataService.RemoveTag(e.Title);
        this.blogPost = this.dataService.GetById(view.BlogPostId);
        view.Tags = blogPost.Tags;
        view.DataBind();
    }

    void OnPostSaved(object sender, EventArgs e)
    {
        Save();
    }

    void OnTagCreated(object sender, EventArgs e)
    {
        CreateAndAddTag();
    }

    void OnViewLoad(object sender, EventArgs e)
    {
        if (!view.IsPostBack)
        {
            LoadViewFromModel();
            view.DataBind();
        }
    }
    
    public Tag GetTagById(int id)
    {
        //Normally we’d probably just have a method 
        //of the service just return this.
        foreach (Tag tag in this.blogPost.Tags)
        {
            if(tag.Id == id)
                return tag;
        }
        return null;
    }

    void LoadViewFromModel()
    {
        this.blogPost = this.dataService.GetById(view.BlogPostId);
        view.Tags = blogPost.Tags;
        view.BlogPostBody = blogPost.Description;
    }
       
    void Save()
    {
        this.dataService.Save(view.BlogPostId, view.BlogPostBody);
        LoadViewFromModel();
        view.DataBind();
    }
    
    void CreateAndAddTag()
    {
        this.dataService.AddTag(view.NewTag);
        //Need to rebind the tags. retrieve tags from db.
        this.blogPost = this.dataService.GetById(view.BlogPostId);
        view.Tags = blogPost.Tags;
        view.NewTag = string.Empty;
        view.DataBind();
    }
}

Implementing the View {.clear}

I have yet to implement the ASP.NET page that will implement the view, yet I am able to write a bunch of unit tests (which I will provide) against the presenter to make sure it behaves appropriately. This is the benefit of this pattern in that much more of the UI logic is now testable.

Implementing the ASP.NET page is pretty straight forward. I drop a few controls on a page, wire up the controls declaratively to their data sources, and then implement the IPostEditView interface. As much as possible, I want to leverage ASP.NET declarative data binding. The point isn’t to force developers to write more code. Here is the code behind for the page. I apologize for the code heaviness of this article.

public partial class _Default : System.Web.UI.Page, IPostEditView
{
    PostEditController controller;
    ICollection<Tag> tags;
    
    public _Default()
    {
         this.controller = 
             new PostEditController(this, new BlogDataService());
    }
    
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    
    public void Update()
    {
        DataBind();
    }

    public int BlogPostId
    {
        get { return GetBlogId(); }
    }
   
    private int GetBlogId()
    {
        string idText = Request.QueryString["id"];
        int result;
        if(int.TryParse(idText, out result))
        {
            return result;
        }
        return 1;
    }

    public string BlogPostBody
    {
        get { return this.txtDescription.Text; }
        set { this.txtDescription.Text = value; }
    }

    public ICollection<Tag> Tags
    {
        get { return this.tags; }
        set { this.tags = value; }
    }

    public string NewTag
    {
        get { return this.txtNewTag.Text; }
        set { this.txtNewTag.Text = value; }
    }
    
    protected void OnSaveClick(object sender, EventArgs e)
    {
        EventHandler postSaved = this.PostSaved;
        if (postSaved != null)
            postSaved(this, EventArgs.Empty);
    }
    
    protected void OnAddTagClick(object sender, EventArgs e)
    {
        EventHandler tagCreated = this.TagCreated;
        if (tagCreated != null)
            tagCreated(this, EventArgs.Empty);
    }

    void OnTagDeleteClick(object source, 
                          RepeaterCommandEventArgs e)
    {
        EventHandler<TagRemovedEventArgs> tagRemoved 
        = this.TagRemoved;
        if(tagRemoved != null)
        {
            string tagTitle 
          = ((Literal)e.Item.FindControl("ltlTag")).Text;
            tagRemoved(this, new TagRemovedEventArgs(tagTitle));
        }
    }

    public event EventHandler TagCreated;

    public event EventHandler PostSaved;

    public event EventHandler<TagRemovedEventArgs> TagRemoved;
    
    protected override void OnInit(EventArgs args)
    {
        this.btnSave.Click += OnSaveClick;
        this.btnNewTag.Click += OnAddTagClick;
        this.rptTags.ItemCommand += OnTagDeleteClick;
    }
}

When I finally compile all this and run it, here is the view I see in the browser.

Blog Post Editor Page

The benefits of this exercise become clear when you find bugs in the UI logic. Even while going through this exercise, I would find minor little bugs that I could expose by writing a failing unit test. I would then fix the bug which would cause the test to pass. That is a great way to work!

As an exercise for the reader, I left in a bug. When you leave the tag textbox blank, but click the Add button, it adds a blank tag. We should just ignore a blank tag. Try writing a unit test that fails because it assumes that a tag will not be added when the NewTag field is left blank. Then make the test pass by fixing the code in the Controller class. Finally, verify that by fixing the unit test, that the actual UI works by trying it out in the browser.

I apologize for glossing over so many details, but I did not want to turn this post into a book. If you want to read more on MVP, check out Bill McCafferty’s detailed treatment at the CodeProject. Also worth checking out is Jeremy D. Miller’s post on Model View Presenter.

Finally, to really understand what I am trying to present here, I encourage you to download the source code and try it out. I have included extensive comments and unit tests. This requires the free Web Application Project Model from Microsoft to compile and run.

The code doesn’t require a database connection, instead simulating a database via some static members. Please understand, that code is just a simulation and is not meant to be emulated in production code.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

90 responses

  1. Avatar for Rudi
    Rudi August 8th, 2006

    Great post, I've been looking for something like this.

  2. Avatar for Mike
    Mike August 8th, 2006

    THanks for your article. One observation...don't you seem to be tying the presenter to the ASP.NET event model? If not, can you use the same presenter for a WinForms app? I know that this requirement may not be a big deal since often only one UI type is the requirement but I know I want to try to use the same presenters for my WinForms as my Web Forms. What are your thoughts on this.
    Thanks for the tip on RhinoMocks handling events, too!
    MIKE

  3. Avatar for Bill Pierce
    Bill Pierce August 9th, 2006

    Phil,
    I'm dabbling with MVP/Supervising Controller in ASP.Net as well. Just some thoughts from my work:
    + Rather than use events on the View, I prefer to pass a reference of the Presenter to the View. This way you have methods on the Presenter like Save(int blogId, string Text) which are called from the View. I find it easier to inject security and validation checks at the Presenter level when the interaction is structured this way.
    + 99% of the properties on my Views are set only. Any data that needs to come from the View is handled through the Presenter methods (like Save above)
    + I don't expose DataBind() on the View. The setter for Tags in your example would call DataBind itself. The trade off to this is other initalization properties may need to be set on the View, before you set the Tags. This further separates the Presenter from the View.
    + You mention making the View responsible for determining which blog to edit by grabbing data from the QueryString. Taking a page from MonoRail you can easily implement an IContext service that wrappes the HttpContext object, giving you access to QueryString parameters, and inject this into your Presenter. The same tactic can be used for other Web specific objects. Again, this allows you to make a security check at the presenter level to make sure the user is allowed to view/edit a blog entry.
    + I do make judicious use of Page/UserControl events like OnInit, OnPreRender but minimally and only when it doesn't make sense to make the Presenter kick off that code
    Sorry for the lengthy reply, and again, just my humble thoughts on the subject.
    -Bill

  4. Avatar for Kevin Dente
    Kevin Dente August 9th, 2006

    >I supplied all the unit tests in the
    >download.
    Oops. Sorry. My bad, I didn't actually look at the code download.

  5. Avatar for Haacked
    Haacked August 9th, 2006

    Thanks for your comments all!
    @Mike: Good question and worthy of its own blog post:
    @Bill: Great tips. Regarding the reference to presenter, in real apps, I sort of mix both events and methods. I stick mostly to events because I can still control security via the event handler code.
    Regarding DataBind(), since I'm focused on ASP.NET, I thought it was an ok trade off. I thought long and hard about it. For what you are doing, you could have a PauseUpdate() and ContinueUpdate() method (or something like that. I forget the corresponding methods in WinForms) so that you could set multiple view properties without calling DataBind each time.
    IContext! Love it!
    @Kevin: I supplied all the unit tests in the download. Maybe I can have a follow up post with just code ;)
    And I love the tip about the events! Awesome!

  6. Avatar for Haacked
    Haacked August 9th, 2006

    @Kevin: One problem with implementing events in the way you proposed is that I can no longer attach events in the constructor of the contrete view because the button hasn't been instantiated yet.

  7. Avatar for Kevin Dente
    Kevin Dente August 9th, 2006

    True. I generally create my presenter in Page_Init, but of course that means you can't handle Init in the presenter without some sort of manual call. Guess I rarely do anything in Page_Init. :)
    Page_PreInit should also work, but again it may complicate handling of that event if you need it.

  8. Avatar for Haacked
    Haacked August 9th, 2006

    Hmmm. I like the idea of Page_PreInit. That might be a worthy trade-off. Who handles Page_PreInit these days anyways?!

  9. Avatar for Scott
    Scott August 9th, 2006

    Fantastic post, Phil.

  10. Avatar for Doubting Naysayer
    Doubting Naysayer August 11th, 2006

    It will never work. Programming is a fad.

  11. Avatar for Scott Elkin
    Scott Elkin August 15th, 2006

    I know this makes me look like a stupid programmer, but I don't get it.
    I mean, this is a lot of work for such a simple form. And because my client (and myself) like to change the page even after it is finished, this adds to the complexity.
    I am all about doing what is "right", but I just don't get this. It would appear to severely lengthen the time it would take to create each page, and make it that much tougher for change requests. All for what exactly?
    Maybe my lack of a CS degree is finally catching up to me. Or the first season of The OC I was forced to watch killed my remaining brain cells that allowed my to understand software patterns.

  12. Avatar for Haacked
    Haacked August 15th, 2006

    Because most UIs aren't this simple.
    I like to change the UI a lot too. This doesn't prevent that. Most UI changes are in the layout and minor tweaks anyways which don't require a lot of code.
    The point of this is to make it more testable in an automated fashion. And by testable, I don't mean where a button goes and such, I mean the important parts. Like how the UI interacts with the user.
    For example, I included unit tests in the source code to demonstrate how this ui is now testable. When you make changes to the UI, you have more confidence that you didn't break another major interaction path if your other tests pass.

  13. Avatar for Haacked
    Haacked August 15th, 2006

    As a followup, I think this approach makes it easier to change the UI.
    The Subtext Admin section does not employ this technique (yet). It uses your traditional ASP.NET technique of some databound controls on a page, events wired up, yadda yadda.
    Yet every time I try to change something, I seem to introduce a bug in something else. The page is very brittle to change. There are no unit tests to let me know that I broke something important.
    Once I refactor the code to be cleaner using this approach, it'll be easier to write unit tests to cover a significant portion of the code paths.
    With that in place, it'll be easier to make changes to the UI. My tests might not catch everything, but they will make sure I don't break the same thing twice.

  14. Avatar for Scott Elkin
    Scott Elkin August 15th, 2006

    I think that is my problem in understanding this. I have not tried to test my UI with unit testing like I need to. I am sure once I try, this solution will be immediately apparent.
    Thanks for the response.

  15. Avatar for Scott Elkin
    Scott Elkin August 17th, 2006

    My services layer is generated for me using .netTiers, and there doesn't seem a way for me to reference an interface from my controller. Each entity implements a generic interface, which prevents me using this.
    For example, if each service entity inherits from:
    interface IEntityProvider<Entity, EntityKey>
    where Entity: IEntityId<EntityKey, new()
    where EntityKey : IEntityKey, new()
    I can't write:
    //IBlogDataService dataService;
    IEntityProvider dataService //compile error or
    IEntityProvider<T,T> // no no no
    My only solution is to pass in the appropriate types. Such as in one case:
    IEntityProvider<Customer, CustomerKey> dataService;
    Is there another way around this other than creating another tier or service interfaces/classes between the controller and my service layer?

  16. Avatar for Andrew Stopford's Weblog
    Andrew Stopford's Weblog August 22nd, 2006

    One of the comments in Phil&#39;s post on using the MVP patten ismappingthe Context object to a typethat

  17. Avatar for Bas Geertsema
    Bas Geertsema August 22nd, 2006

    Great post. I have been implementing this pattern myself recently for a project. However I do not work with events in the view interface, but the view will call the controller. These calls contains no parameters; the necessary data (selected tag id, etc) is requested by the presenter by making calls back to the view. I can't say at this point which method works betters, but I felt comfortable with it.
    As a reply on a previous post: no in this case it is not really worth the effort. However UI's tend to become increasingly complex with little subtle logic flows. One way or another you will probably write the code anyway, so you might as well factor it out in a seperate class. And you get testing possibilities for free.
    Other techniques I use:
    - Testing is being done with the use of NMock to stub the interfaces of the view and repositories (dataservice in this case).
    - For more complex logic flows you can use the State pattern in which you delegate events to a state object that can easy decide what to do based on it's state. (For example: not all events are possible/legitimate in all states).
    More info about the MVP pattern and state pattern can be found in the excellent book of Robert C. Martin ('Agile Software Development').

  18. Avatar for Jesse Ezell Blog
    Jesse Ezell Blog August 23rd, 2006

    Andrew Stopford asks:One of the comments in Phil&#39;s post on using the MVP patten ismappingthe Context

  19. Avatar for Artur Carvalho
    Artur Carvalho October 1st, 2006

    IMHO there is a problem in using events instead of the " Initialize method", is the handling of exceptions.
    What's is your approach to exception handling?

  20. Avatar for Haacked
    Haacked October 1st, 2006

    Not sure I understand? For example, the Load event is handled by:
    void OnViewLoad(object sender, EventArgs e);
    In that method I can handle any exceptions and update the view accordingly.

  21. Avatar for Dave
    Dave October 8th, 2006

    Phil, I finally got around to creating a version of your example that uses the StateChart concept (and ViewMachine). The code is available for download from my site. And I wrote an article on my site comparing the StateChart-based approach to the Supervising Controller approach you used. They are similar in terms of the amount of effort required to implement (which is not too much). For anyone that understands the power of StateCharts in the UI, this is very good news -- because that power is available at no extra cost. I hope my article demonstrates this fact clearly. I would love to hear your feedback, and I'll probably update the article (and code) based on the feedback.
    See http://www.viewmachine.com

  22. Avatar for Brian Donahue
    Brian Donahue October 11th, 2006

    Hi Phil,
    I'm working on a project now where I am using a lot of the ideas from your post, as well as from Jean-Paul Boodhoo's posts on MVP and others. I was curious - when testing a Load event that may require a lot of interaction with the view (databinding, show/hiding controls, etc) do you put all of the expectations in one test? My test is pretty big, and doesn't seem clear to me now, and it would seem more clean to have specific requirements broken out in different tests, like "ShouldBindStateDropdown" and "ShouldHidePOBoxFieldWhen[Whatever]". The only way I can think of to do that is to have several tests that test the Load event, set only the expectations for that specific test, and ignore all other calls on the mock object that may occur before/after your expected calls. Is that a valid approach? Is there a better way?

  23. Avatar for Haacked
    Haacked October 11th, 2006

    Brian, I think that's a great way to go! Just remember to use the SetupResult.On() to setup the return values for methods that you don't care to test an expectation on.

  24. Avatar for you've been HAACKED
    you've been HAACKED October 18th, 2006

    Interesting Perf Lesson

  25. Avatar for Jiho Han
    Jiho Han October 21st, 2006

    Thanks for the post.
    Would you mind doing a Passive View version of the sample just so that it would be easy to make a comparison and understand the difference?

  26. Avatar for Andrew Stopford's Weblog
    Andrew Stopford's Weblog October 25th, 2006

    It was bound to happen sooner or later, someone comparing webforms to monorail. All of the pro&amp;#39;s

  27. Avatar for Mike Diehl's WebLog
    Mike Diehl's WebLog October 26th, 2006

    Haacked has a great article on the nuts-and-bolts of building ASP.NET pages using the MVC pattern and

  28. Avatar for Ian Cooper
    Ian Cooper October 26th, 2006

    Great post, but our usage of the pattern is far simpler. We create a presenter reference in the view and pass it the view it is in along with the model.
    Our tests then tend to represent actions on the UI for example DisplayLogs and we use the mocks the check for the interaction with the model and the view.
    We still achieve the same goal, a thin UI, and testing of our UI logic, but I would say that we are more UI independent because we make no assumptions about whether the view is Webform or Winform.
    Render unto Ceaser the things that are Ceasers.
    The other point to be aware of is that anything you can do with a delegate you can do with an interface i.e. the observer pattern. In many cases its more testable.

  29. Avatar for can't print it
    can't print it October 27th, 2006

    Try to print your post and you will only get one page of it the rest is the comments most people don't care. Seems some bug with your blog engine(IE7 & FF2 behave same) ?

  30. Avatar for sadek drobi
    sadek drobi November 27th, 2006

    more suggestions about the model view presenter on www.sadekdrobi.com

  31. Avatar for Sean Chambers
    Sean Chambers December 7th, 2006

    I like your approach with using events to drive the controller. It seems like a much more object oriented approach of an event model.
    Once question I have though that was not covered in your post, where would you run validation checks? I assume in the view? or would that task be sent to the domain model to check against the specific domain objects?
    Thats for the posting! I'm trying to implement it in my next project and so far so good!
    Sean

  32. Avatar for Haacked
    Haacked December 7th, 2006

    Personally, I use Validator controls for the first round of checks. The second round occurs in the domain layer.
    Yeah, it's a small bit of logic duplication. Apparently Microsoft is releasing a Validation Application Block. I need to look at that to see if it helps.

  33. Avatar for DotNetKicks.com
    DotNetKicks.com December 7th, 2006

    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  34. Avatar for vikram
    vikram December 7th, 2006

    Hmmm Good example , well documented

  35. Avatar for Chyld
    Chyld December 7th, 2006

    Excellent article!

  36. Avatar for Nandu
    Nandu December 8th, 2006

    Why do we pass the service instance from view to the presenter? Why can't we create the service instance in the presenter itself? Is there any advantage in doing the way you did? Thanks for posting such good article.
    If i can request, can you post some article on using RhinoMocks - especially interacting with database?
    Thanks again

  37. Avatar for MK2
    MK2 December 19th, 2006

    MVP——Model-Viewer-Presenter

  38. Avatar for DotNetKicks.com
    DotNetKicks.com December 20th, 2006

    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  39. Avatar for Micka&#235;l
    Micka&#235;l January 18th, 2007

    Great post!!
    Just a simple comment on
    view.Load += OnViewLoad;
    ...that I would replace by:
    View.Load += new System.EventHandler(OnViewLoad);
    This allow aggregation of presenter to avoid duplication of code. For exampel, if you have a ListPresenter and would like to create ListAndDetailPresenter. So in the detail and list presenter, you will create a list presenter so share the code, and also register the ListAndDetailPresenter to the onload event of the view to bind the detail data. I prefer use aggregation than inheritance, just as the ListAndDetailPresenter may want to hid some of the ListPresenter events.
    If you do not change the event registration, the ListAndDetailPresneter will never be called.

  40. Avatar for Kas
    Kas January 29th, 2007

    Excellent post. Thanks very much for the detailed example. I'm still having some trouble understanding how I would implement MVP on a presenter which must control the activities of a hirearchy of Domain Model Entities (i.e Person has * ContactInformation and ContactInformation has * Telephone and implementing a single presenter which can capture the user creating X number of ContactInformation with X number of Telphone and persisting that interaction through the service layer).
    Just wondering about your example, if you have a property on the view called IsPostBack, isn't that specific to asp.net? The view should probably not be bound to any specific interface implementation maybe a better name would have been IsInitialized or something similar.

  41. Avatar for Haacked
    Haacked January 29th, 2007

    Yes, IsPostBack is tied to ASP.NET. I did that on purpose, which I explain in a follow-up post.

  42. Avatar for Polymorphic Podcast
    Polymorphic Podcast March 7th, 2007

    Design Patterns Bootcamp: Model View * Patterns Listen to the Show! Thanks to Dave Bost for the intro!

  43. Avatar for Craig Shoemaker
    Craig Shoemaker March 7th, 2007

    Design Patterns Bootcamp: Model View * Patterns<br />Listen to the Show!<br /><br />Thanks to Dave Bost for the intro!...

  44. Avatar for Console.Write(this.Opinion)
    Console.Write(this.Opinion) March 18th, 2007

    Outro dia respondi uma pergunta no f&#243;rum MSDN sobre desenvolvimento em camadas. Meu &#250;nico conselho para

  45. Avatar for David Tchepak
    David Tchepak March 28th, 2007

    Hi Phil,
    Thanks for the great example. I am a TDD newbie (done lots of research but struggling to put it into practice) and am trying to reproduce this example from scratch. In the process I am running into difficulties and was hoping you could give me some hints.
    Firstly, the purist TDD approach seems to be "don't write code without a failing test". I have a lot of trouble getting going without writing at least a view interface first without a test so I can start working on the controller (as you appear to have done). Is this just a case of needing to be more realistic than following the letter of the gospel-according-to-Beck? :)
    I also tend to end up writing a BlogPost class and basic "IBlogRepository" (model/data access interface which I stub out) pretty quickly without directly required to do so by a test.
    Basically I end up taking big steps to implement LoadPost and SavePost tests. I would like to code it in smaller steps but in this example and in others I try I always end up getting stuck with large steps. I'd love to get any hints you have on this.
    Regards,
    David

  46. Avatar for Haacked
    Haacked March 28th, 2007

    It's a case of personal preference. Obviously, if you don't write the view interface, your test won't even compile. In a purist TDD sense, that qualifies as a failing test.
    Personally, I like my tests to compile as the "fail" part, so I usually define the beginning of the interface, write a test that complies, make sure the test fails, then move on. I allow myself to refine the interface as I write tests recognizing it as an iterative process.
    I try to keep the steps as small as possible. Sometimes a decent size step is "as small as possible". I'll try to find some time to walk through a real world example of TDD one of these days.

  47. Avatar for Develop Better
    Develop Better April 14th, 2007

    ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests to Code

  48. Avatar for Community Blogs
    Community Blogs May 12th, 2007

    Yesterday Phil Haack posted up this nice post about how to code the MVP pattern in a web application.

  49. Avatar for Chris May
    Chris May May 25th, 2007

    If you run asp.net unit tests (the tests that are built into vs 2005), then doesn't that solve a lot of the issues of how to test things that rely on the asp.net framework?
    For example, you can test the objects in the view without creating a mock for it right?
    Also, if you are doing an MVP setup and you want to databind a dataset to a gridview, would you pass the dataset from the Presenter to the View into a method like DatabindResults(dataSet) and the view would perform the databind?

  50. Avatar for Tyler Gannon
    Tyler Gannon June 12th, 2007

    Phil,
    This post and subsequent conversations helped me a lot in writing well-tested and readable code. Thanks! The new question I have is - do you see any way to fit SubSonic's generated DAL into this pattern?
    I am feeling a little annoyed that, as far as I can tell, Subsonic's fetch methods are on constructors and static methods of the object. This means that I have to write another Very Generic adaptor to those methods if I am going to create interfaces which can be passed around like you describe.
    Is there another way to do this, that I have been missing thus far?
    Tyler

  51. Avatar for caesar
    caesar June 13th, 2007

    Nice post, exactly what i need. I apologize for stupid question, i didn't use unit testing before... What tool should I use to check tests ?

  52. Avatar for Haacked
    Haacked June 13th, 2007

    I recommend installing MbUnit and TestDriven.NET.

  53. Avatar for sitem00n
    sitem00n July 3rd, 2007

    the EventHandler Init was not implemented in the page, how can this work?

  54. Avatar for Haacked
    Haacked July 3rd, 2007

    Because the System.Web.UI.Page class implements Init.

  55. Avatar for My blog
    My blog July 17th, 2007

    ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests to Code

  56. Avatar for BlogCoward
    BlogCoward July 26th, 2007

    Dislike of hand-writing HTML != Like Drag and Drop Designing

  57. Avatar for Alexey Romanov
    Alexey Romanov August 24th, 2007

    Can IPostEditView have reference to a BlogPost instead of BlogPostBody, Tags, and BlogPostId?
    Or should this be avoided?

  58. Avatar for Slevdi
    Slevdi October 13th, 2007

    On tying to grock this, I see a 'Customer Complaint Form' mentioned in the source. Is this part of the solution or, as I suspect, something leftover from another project which I can ignore or replace with 'Blog Post Form'?

  59. Avatar for dave^2=-1
    dave^2=-1 January 31st, 2008

    Very nice article by Phil Haack: ASP.NET Supervising Controller (Model View Presenter) From Schematic

  60. Avatar for Ran Davidovitz
    Ran Davidovitz February 6th, 2008

    Phil very professional and Simple to understand article.
    I am in a point that i doing a POC of MVP for one of our project,
    I found that it complex the project BUT at the end it will reduce time of serviceability and maintainability through TDD.
    Thanks

  61. Avatar for Justin
    Justin February 19th, 2008

    Thanks Phil,
    I have been struggling with this pattern. I have been reading Jeremy Miller's "Create your own CAB" series which covers this also but he assumes a lot of knowledge and his examples are over my head.
    This was a nice straight forward example. It helped a lot!

  62. Avatar for Roberto Lopes
    Roberto Lopes April 12th, 2008

    Hi,
    Great article. I am just wondering how should ajax methods work using MVP. Ajax brings the ability to avoid browser roundtrips, therefore some logic are usually embedded in the presentation layer to change the page behaviour, like depending on the selection in the dropdown list, you populate a second dropdown list or something like that.
    How it would work when using a MVP (supervising controller)? Not always the code is pure C#. Sometimes we need some JavaScript.
    Thanks,
    Roberto Lopes

  63. Avatar for Hieu Nguyen
    Hieu Nguyen April 22nd, 2008

    Hi Phil,
    Great post!, I came from Java world so the Event thing is a little hard for me to wrap my head around. Hope you can shed some light.
    From your example in the method OnAddTagClick of the _Default class, why do you have a check if the tagCreated is null? I thought we don't have to check for that because in the PostEditController, we already subcribe a method to the event?

  64. Avatar for Oleg Zhukov
    Oleg Zhukov April 24th, 2008

    Short and clear explanation, very nice! Though some of the tasks described here may be automated with the help of a Model-View-Presenter framework such as MVC# Framework.

  65. Avatar for ASP
    ASP May 17th, 2008

    Excellent Post with good examples!
    Keep up the good work!

  66. Avatar for Nguyễn Thoại
    Nguyễn Thoại June 17th, 2008

    Thanks for greate post.
    However, i have read a lot pages about Supervising Controller and Passive View but i could not determine the differences between them.
    Could you please make another entry about Passive View?

  67. Avatar for Nguy&#225;&#187;…n Tho&#225;&#
    Nguy&#225;&#187;…n Tho&#225;&# June 18th, 2008

    I think i found the answer.
    There is a very clearly MSDN paper about this issue:
    msdn.microsoft.com/en-us/library/cc304728.aspx :D
    Thank you anyway.

  68. Avatar for Andrew
    Andrew July 7th, 2008

    Hello, I'm new to .NET and am findng this post very helpful.
    One question I have is: How/where is the _Default.Update() method invoked? I don't see any other references to this anywhere.
    Thanks,
    Andrew

  69. Avatar for gazza
    gazza August 13th, 2008

    Hi and thank you for a great post.
    I'm using vb.net and cannot get the IView interface working.
    I've no problem with the Init/Load events but IsPostBack, IsValid and DataBind requires the page where I implement the interface to implement these properties/subs.
    Here's my vb.net code:

    Public Interface IView
    Delegate Sub Init(ByVal sender As Object, ByVal e As EventArgs)
    Delegate Sub Load(ByVal sender As Object, ByVal e As EventArgs)
    ReadOnly Property IsPostBack() As Boolean
    Sub DataBind()
    ReadOnly Property IsValid() As Boolean
    End Interface

    The specific error message is:
    Class 'MyPage' must implement 'ReadOnly Property IsValid() As Boolean' for interface 'IView'. Implementing property must have matching 'ReadOnly' or 'WriteOnly' specifiers.
    Somebody who knows how to write the proper interface to get this working?
    Thanks,

  70. Avatar for Eduardo Xavier
    Eduardo Xavier September 9th, 2008

    I just would like to say that you added some lines of code to accomplish simples things. This is example is not really abtracting layers to simplying tests, it just increasing line of codes and can be a future headaches for a devolpment team.
    But this post still giving a clear undestanding about how to do MVP on ASP.NET and de facto is very nice work afterall.
    Best

  71. Avatar for Jimit Ndiaye
    Jimit Ndiaye September 10th, 2008

    @Haacked:
    This is an excellent post. I do believe, however, that the implementation sounds alot more like Passive View than Supervising Controller: no interaction between view and model, no knowledge of the presenter by the view, using events to communicate user interactions...

  72. Avatar for discover
    discover September 29th, 2008

    I'm currently trying to learn the Supervising Controller pattern, and was wondering how to do authentication when using this pattern? I can't seem to find anything on this subject on the net.
    thanks!

  73. Avatar for aviade
    aviade October 31st, 2008

    Hi Phil
    I enjoyed reading your post as always.
    I read your post and downloaded the source code and in my opinion the pattern that you are implementing there looks more like ‘passive view’ than ‘supervising controller’.
    With ‘supervising controller’ in most cases the view is in charge of updating its display (like after post is saved), the controller updates the view display only where more complex logic involved (example for complex logic is – reading model state and deciding how to change the view), with ‘passive view’ on the other hand - the presenter alone is in charge of updating the view.
    So in my opinion, MVP should be called ‘supervising controller’ to stress the point that the view has the responsibility to stay synchronized with model data, if that is not the case - the pattern should be called ‘passive view’ so we'll know that the presenter is in charge of the entire workflow and it is the one that got the responsibility to update the view.
    In your post (like in most ASP.NET solutions) the view has (and should have) no interaction with the model so ‘supervising controller’ is not the best name - even though it is not a mistake.

  74. Avatar for Sven
    Sven December 16th, 2008

    @discover:
    I've been working with MVP for quite some time, lossely based on this one, and i'm doing a series of posts on it. I just did one on the authentication, so check out : www.qsoft.be/.../...ion-with-2-lines-of-code-.aspx
    I hope it helps you out !

  75. Avatar for Edward
    Edward December 28th, 2008

    I agree that this is an example of Passive View rather than Supervising Controller.
    Since Webforms databinding is essentially read-only, I was wondering how the Supervising Controller pattern could be easily implemented. Unlike Winforms, the 'model' does not get modified as databound controls are interacted with and so the presenter must obtain any user input in one of two ways:
    - A specialized EventArgs on the View events (or a parameterized method on the presenter if calling directly without events)
    - By directly requesting the input from the View.
    Neither solution feels like Supervising Controller to me.
    Great article and example of Passive View, Phil :)

  76. Avatar for Ira
    Ira February 11th, 2009

    Phil,
    Thank you so much for this post. I have been reading so much about ASP.NET MVC lately but am unable to bring myself to deploy a beta or RC into a production environment. This pattern and example has helped me write better and more testable code for my ASP.NET webforms. Thanks again, and keep up the great work!

  77. Avatar for Bin
    Bin December 15th, 2009

    Thanks Rob! I can not unzib your source code downloaded from here.
    message error: "Either multipart or corrupt ZIP archieve".
    Please help me!

  78. Avatar for Creator
    Creator December 17th, 2009

    Hi zip is corrupted!!! People I need this code really ))!!

  79. Avatar for Will
    Will December 17th, 2009

    Interesting article! Looks like your recent crash took out the source code zip. If you code restore it, that would be helpful! Thanks!

  80. Avatar for Todd Taylor
    Todd Taylor December 17th, 2009

    For those of you who are using this supervising controller design pattern, what are you doing for CSS on your website... I.e., the ASP.NET Page.theme property doesn't seem to work using the supervising controller when a page theme is added to the code provided with this blog post. Has anyone figured-out a way to use themes and the supervising control? :-S

  81. Avatar for gurjeet
    gurjeet February 12th, 2010

    hi there....the source code(download file) has errors you basically cannot open the compressed file.can u pls add another source code file for download pls?

  82. Avatar for Neil
    Neil July 28th, 2010

    Your source code download link seems to be 404'ing. :(

  83. Avatar for dalvarez
    dalvarez August 17th, 2010

    I cannot download the source code... It's missing. Can you reupload it?

  84. Avatar for Jim Harte
    Jim Harte August 30th, 2010
  85. Avatar for Danilo
    Danilo November 15th, 2010

    I couldn´t download it, could you show another link to download? tks!

  86. Avatar for Bryan Hadlock
    Bryan Hadlock December 6th, 2010

    Still can't get the code

  87. Avatar for andrew
    andrew February 1st, 2012

    Hi Phil.
    I'm wondering how the implementation will be changed in case of the Passive View?

  88. Avatar for sathish
    sathish February 8th, 2012

    Hi Phil,I was wondering how to hock up the calls to view from jquery?

  89. Avatar for Josh
    Josh February 14th, 2013

    This is great post. I have one question, I see the events are register using += notation, however I don't see them being unregistered. Would that lead to memory leak ? If yes, does the class need to follow Dispose Pattern and then you can unregister the events. Let me know.

  90. Avatar for nguyencaoan
    nguyencaoan August 20th, 2013

    thanks you