Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Model View Presenter with ASP.NET

, 16 Oct 2007
This article describes using the Model-View-Presenter pattern within ASP.NET 2.0 to encourage proper separation of concerns between presentation and business logic
amosttrivialexample.zip
AMostTrivialExample
App_Code
Solution Items
nunit.framework.dll
enterpriseapplicationmvp.zip
EnterpriseApplicationMvp
MvpSample.Core
bin
Debug
Castle.DynamicProxy.dll
Iesi.Collections.dll
log4net.dll
MvpSample.Core.dll
MvpSample.Core.pdb
NHibernate.dll
NHibernate.Generics.dll
DataInterfaces
Domain
Properties
MvpSample.Data
bin
Debug
Castle.DynamicProxy.dll
Iesi.Collections.dll
log4net.dll
MvpSample.Core.dll
MvpSample.Core.pdb
MvpSample.Data.dll
MvpSample.Data.pdb
NHibernate.dll
NHibernate.Generics.dll
Properties
MvpSample.Presenters
bin
Debug
Castle.DynamicProxy.dll
Iesi.Collections.dll
log4net.dll
MvpSample.Core.dll
MvpSample.Core.pdb
MvpSample.Presenters.dll
MvpSample.Presenters.pdb
NHibernate.dll
NHibernate.Generics.dll
Properties
ViewInterfaces
MvpSample.Tests
bin
Debug
Castle.DynamicProxy.dll
Iesi.Collections.dll
log4net.dll
MvpSample.Core.dll
MvpSample.Core.pdb
MvpSample.Data.dll
MvpSample.Data.pdb
MvpSample.Presenters.dll
MvpSample.Presenters.pdb
MvpSample.Tests.dll
MvpSample.Tests.pdb
NHibernate.dll
NHibernate.Generics.dll
Data
Domain
MockDao
Presenters
Properties
MvpSample.Web
App_Code
Bin
Castle.DynamicProxy.dll
Castle.MicroKernel.dll
Castle.MicroKernel.dll.refresh
Castle.Model.dll
Castle.Model.dll.refresh
Castle.Windsor.dll
Castle.Windsor.dll.refresh
Iesi.Collections.dll
Iesi.Collections.dll.refresh
log4net.dll
log4net.dll.refresh
MvpSample.Core.dll
MvpSample.Core.pdb
MvpSample.Data.dll
MvpSample.Data.pdb
MvpSample.Presenters.dll
MvpSample.Presenters.pdb
NHibernate.dll
NHibernate.Generics.dll
Config
Global.asax
Views
Solution Items
Castle.MicroKernel.dll
Castle.Model.dll
Castle.Windsor.dll
Iesi.Collections.dll
log4net.dll
NHibernate.dll
NHibernate.Generics.dll
nunit.framework.dll
eventhandlingmvp.zip
EventHandlingMvp
App_Code
Solution Items
nunit.framework.dll
Views
using System;
using MvpSample.Core.DataInterfaces;
using MvpSample.Core.Domain;
using MvpSample.Presenters.ViewInterfaces;

namespace MvpSample.Presenters
{
    /// <summary>
    /// There's not a lot of reason to separate the "Edit" presenter from the "Add" presenter; but alas, 
    /// it makes for a more thorough example.
    /// </summary>
    public class AddCustomerPresenter
    {
        public AddCustomerPresenter(IAddCustomerView view, ICustomerDao customerDao) {
            if (view == null) throw new ArgumentNullException("view may not be null");
            if (customerDao == null) throw new ArgumentNullException("customerDao may not be null");

            this.view = view;
            this.customerDao = customerDao;
        }

        /// <summary>
        /// Raised when the user wants to cancel adding a new customer.  The containing ASPX page should 
        /// listen for this event.
        /// </summary>
        public EventHandler CancelAddEvent;

        /// <summary>
        /// Raised after the customer has been successfully added to the database.
        /// </summary>
        public EventHandler AddCustomerCompleteEvent;
        
        public void InitView() {
            view.Message = "Use this form to add a new customer.";
        }

        /// <summary>
        /// Called by the view; this grabs the updated customer from the view and commits it to the DB.
        /// </summary>
        public void AddCustomer(bool isPageValid) {
            // Be sure to check isPageValid before anything else
            if (! isPageValid) {
                view.Message = "There was a problem with your inputs.  Make sure you supplied everything and try again";
                return;
            }

            if (! IsDuplicateOfExisting(view.CustomerToAdd)) {
                customerDao.Save(view.CustomerToAdd);

                // You could certainly pass in more than just null for the event args
                AddCustomerCompleteEvent(this, null);
            }
            else {
                // By passing HTML tags from the presenter to the view, we've essentially bound the 
                // presenter to an HTML context.  You may want to consider alternatives to keep the 
                // presentation layer web/windows agnostic.
                view.Message = "<span style=\"color:red\">The ID you provided is already in use.</span>  " +
                               "Please change the ID and try again.";
            }
        }

        /// <summary>
        /// Checks if a customer already exists with the same customer ID.
        /// </summary>
        private bool IsDuplicateOfExisting(Customer newCustomer) {
            // Whenever possible, I *really* don't like using assigned IDs.  I think they 
            // should only be used when working with a legacy database.  Among other ugliness, 
            // assigned IDs force us to try/catch when checking for duplicates because NHibernate 
            // will throw an ObjectNotFoundException if no entity with the provided ID is found.
            // Consequently, we also have to have a reference to the NHibernate assembly from within
            // our business object.
            // To overcome these drawbacks, I'd recommend adding a DoesEntityExist(string assignedId) 
            // method to the DAO to check for the existence of entities by its assigned ID.  This would remove the
            // ugly try/catch from this method and it would also remove the local dependency on the NHibernate
            // assembly.  I've chosen not to go ahead and do this because my assumption is that
            // the use of assigned IDs will be the exception rather than the norm...so I want to keep
            // the generic DAO as clean as possible for the example demo.
            try {
                Customer duplicateCustomer = customerDao.GetById(newCustomer.ID, false);
                return duplicateCustomer != null;
            }
            // Only catch ObjectNotFoundException, throw everything else.
            catch (NHibernate.ObjectNotFoundException) {
                // Since the duplicate we were looking for wasn't found, then, through difficult 
                // logical deduction, this object isn't a duplicat
                return false;
            }
        }
        
        /// <summary>
        /// In this example solution, this is simply a pass-through method for the event
        /// to be raised.  In such a simple example, you may consider having the user control raise
        /// the event directly.  Conversely, there are times when other actions are taken before
        /// the event is raised.  In these situations, the presenter should definitely manage 
        /// raising the event after the other actions have been taken.
        /// </summary>
        public void CancelAdd() {
            CancelAddEvent(this, null);
        }

        private IAddCustomerView view;
        private ICustomerDao customerDao;
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Billy McCafferty
Web Developer
United States United States
No Biography provided

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 16 Oct 2007
Article Copyright 2006 by Billy McCafferty
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid