Click here to Skip to main content
15,886,689 members
Articles / Web Development / ASP.NET

Implementing Model-View-Presenter in ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.80/5 (27 votes)
17 Nov 2007CPOL12 min read 129.5K   2.7K   120  
Three implementations of Model-View-Presenter in ASP.NET 2.0.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Data.Common;
using SubSonic.Utilities;

namespace SubSonic
{

    /// Big thanks to Brenton Webster the code contained herein...
    /// <summary>
    /// Indicates that a per-thread shared DbConnection object should be used the default DataProvider
    /// (or alternativley a specific DataProvider if one is given) when communicating with the database.
    /// 
    /// This class is designed to be used within a using () {} block and in conjunction with a TransactionScope object.
    /// It's purpose is to force a common DbConnection object to be used which has the effect of avoiding promotion 
    /// of a System.Transaction ambient Transaction to the DTC where possible.
    /// 
    /// When this class is created, it indicates to the underlying DataProvider that is should use a shared DbConnection
    /// for subsequent operations. When the class is disposed (ie the using() {} block ends) it will indicate to the 
    /// underlying provider that it should no longer it's current shared connection and should Dispose() it.
    /// </summary>
    public class SharedDbConnectionScope
         : IDisposable
    {
        private bool _disposed;
        private DataProvider _dataProvider;

        /// <summary>
        /// Used to support nesting. By keeping a stack of all instances of the class that are created on this thread
        /// thread we know when it is safe to Reset the underlying shared connection.
        /// </summary>
        [ThreadStatic]
        private static Stack<SharedDbConnectionScope> __instances;

        /// <summary>
        /// Provides access to underlying connection that is shared per thread
        /// </summary>
        public DbConnection CurrentConnection
        {
            get { return _dataProvider.CurrentSharedConnection; }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    // remove this instance from the stack
                    __instances.Pop();

                    // if we are the last instance, reset the connection
                    if (__instances.Count == 0)
                        _dataProvider.ResetSharedConnection();

                    _disposed = true;
                }
            }
        }

        /// <summary>
        /// Indicates to the default DataProvider that it should use a per-thread shared connection.
        /// </summary>
        public SharedDbConnectionScope()
            : this(DataService.Provider)
        {
        }

        /// <summary>
        /// Indicates to the default DataProvider that it should use a per-thread shared connection using the given connection string.
        /// </summary>
        /// <param name="connectionString"></param>
        public SharedDbConnectionScope(string connectionString)
            : this(DataService.Provider, connectionString)
        {
        }

        /// <summary>
        /// Indicates to the specified DataProvider that it should use a per-thread shared connection.
        /// </summary>
        /// <param name="dataProvider"></param>
        public SharedDbConnectionScope(DataProvider dataProvider)
        {
            if (dataProvider == null)
                throw new ArgumentNullException("dataProvider");

            _dataProvider = dataProvider;
            _dataProvider.InitializeSharedConnection();

            if (__instances == null)
                __instances = new Stack<SharedDbConnectionScope>();
            __instances.Push(this);
        }

        /// <summary>
        /// Indicates to the specified DataProvider that it should use a per-thread shared connection using the given connection string.
        /// </summary>
        /// <param name="dataProvider"></param>
        /// <param name="connectionString"></param>
        public SharedDbConnectionScope(DataProvider dataProvider, string connectionString)
        {
            if (dataProvider == null)
                throw new ArgumentNullException("dataProvider");
            if (connectionString == null)
                throw new ArgumentNullException("connectionString");
            if (String.IsNullOrEmpty(connectionString))
                throw new ArgumentException("connectionString can not be empty");

            _dataProvider = dataProvider;
            _dataProvider.InitializeSharedConnection(connectionString);

            if (__instances == null)
                __instances = new Stack<SharedDbConnectionScope>();
            __instances.Push(this);
        }
    }

    /// <summary>
    /// Used within SubSonic to automatically manage a SqlConnection. If a shared connection is available 
    /// for the specified provider on the current thread, that shared connection will be used. 
    /// Otherwise, a new connection will be created.
    /// Note that if a shared connection is used, it will NOT be automatically disposed - that is up to the caller.
    /// Lifetime management of the shared connection is taken care of by using a <see cref="SharedDbConnectionScope"/> 
    /// If a new connection is created, it will be automatically dsiposed when this AutomaticConnectionScope object
    /// is disposed.
    /// </summary>
    internal class AutomaticConnectionScope
        : IDisposable
    {
        private DbConnection _dbConnection;
        private bool _isUsingSharedConnection;
        private bool _disposed;

        internal DbConnection Connection
        {
            get { return _dbConnection; }
        }

        internal bool IsUsingSharedConnection
        {
            get { return _isUsingSharedConnection; }
        }

        internal AutomaticConnectionScope(DataProvider provider)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");

            if (provider.CurrentSharedConnection != null)
            {
                _dbConnection = provider.CurrentSharedConnection;
                _isUsingSharedConnection = true;
            }
            else
                _dbConnection = provider.CreateConnection();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    // only dispose the connection if it is not a shared one
                    if (!_isUsingSharedConnection)
                        _dbConnection.Dispose();
                    _disposed = true;
                }
            }
        }

        public T GetConnection<T>()
            where T : DbConnection
        {
            return (T)Connection;
        }
    }

}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions