Click here to Skip to main content
15,891,136 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.6K   2.7K   120  
Three implementations of Model-View-Presenter in ASP.NET 2.0.
///////////////////////////////////////////////////////
// Code author: Martin Lapierre, http://devinstinct.com
///////////////////////////////////////////////////////

using System;
using System.CodeDom;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using SubSonic.Utilities;

namespace SubSonic
{
    /// <summary>
    /// Provides the features required for code generation. 
    /// </summary>
    public interface ICompileUnitGenerator
    {
        #region Methods

        /// <summary>
        /// Generates the DAL in a single CodeCompileUnit from an input file.
        /// </summary>
        /// <param name="languageType">The language to generate the DAL for.</param>
        /// <param name="inputFile">The path to the input file.</param>
        /// <returns>A single CodeCompileUnit.</returns>
        CodeCompileUnit GenerateSingleUnit(LanguageType languageType, string inputFile);

        /// <summary>
        /// Generates the DAL in multiple CodeCompileUnits from an input file.
        /// </summary>
        /// <param name="languageType">The language to generate the DAL for.</param>
        /// <param name="inputFile">The path to the input file.</param>
        /// <returns>A dictionary of suggested filenames/CodeCompileUnit pairs.</returns>
        IDictionary<string, CodeCompileUnit> GenerateMultipleUnits(LanguageType languageType, string inputFile);

        /// <summary>
        /// Generates the DAL in multiple CodeCompileUnits for specific tables, views
        /// and, optionnaly, all stored procedures.
        /// </summary>
        /// <param name="languageType">The language to generate the DAL for.</param>
        /// <param name="tables">
        /// The list of tables to generate the DAL for; first element as "*" for all tables.
        /// Can be null or empty. A null value generates no table and no table struct. 
        /// <param name="views">
        /// The list of views to generate the DAL for; first element as "*" for all views.
        /// Can be null or empty. A null value generates no view and no view struct. 
        /// </param>
        /// <param name="useSPs">
        /// true to generate the Stored Procedure; false not to generate.
        /// A null value generates Stored Procedures based on the configuration file option.
        /// </param>
        /// <param name="providerName">
        /// The name of the provider to generate the DAL for.
        /// If null, generates code for all the providers.
        /// </param>
        /// <returns>A dictionary of suggested filenames/CodeCompileUnit pairs.</returns>
        IDictionary<string, CodeCompileUnit> GenerateMultipleUnits(LanguageType languageType, string[] tables, string[] views, bool? useSPs, string providerName);

        /// <summary>
        /// Gets the list of tables.
        /// </summary>
        /// <param name="providerName">
        /// The name of the provider to get the tables for.
        /// If null, uses the default provider.
        /// </param>
        /// <returns>A list of table names.</returns>
        string[] GetTableNames(string providerName);

        /// <summary>
        /// Gets the list of views.
        /// </summary>
        /// <param name="providerName">
        /// The name of the provider to get the views for.
        /// If null, uses the default provider.
        /// </param>
        /// <returns>A list of view names.</returns>
        string[] GetViewNames(string providerName);

        /// <summary>
        /// Gets the list of provider names for the current application context.
        /// </summary>
        /// <returns>A list of provider names.</returns>
        string[] GetProviderNames();

        #endregion Methods
    }

    /// <summary>
    /// Hosts the code generation process for any environment.
    /// </summary>
    /// <remarks>
    /// This host allows multiple SubSonic code generators 
    /// to run simultaneously even if the SubSonic core classes are static.
    /// </remarks>
    public class CompileUnitGeneratorHost //: ICompileUnitGenerator
    {
        #region Fields

        /// <summary>
        /// The type of the internal generator.
        /// </summary>
        /// <remarks>
        /// More reliable than using a hard-coded string.
        /// </remarks>
        private static Type _generatorType = typeof(CompileUnitGenerator);

        /// <summary>
        /// The hosted compile unit generator.
        /// </summary>
        private ICompileUnitGenerator _generator = null;

        #endregion Fields


        #region Constructors

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="path">The path to the project to create the host for.</param>
        public CompileUnitGeneratorHost(string path)
        {
            _generator = CreateGenerator(path);
        }

        #endregion Constructors


        #region Properties

        /// <summary>
        /// Gets the hosted compile unit generator.
        /// </summary>
        public ICompileUnitGenerator Generator
        {
            get { return _generator; }
        }

        #endregion Properties


        #region Methods

        /// <summary>
        /// Creates a CompileUnitGenerator in its own domain.
        /// </summary>
        /// <remarks>
        /// Assigns the configuration file with the highest priority to the newly created AppDomain.
        /// </remarks>
        /// <param name="path">The path to the project to create the generator for.</param>
        /// <returns>The CompileUnitGenerator.</returns>
        [MethodImpl(MethodImplOptions.NoInlining)] // Make sure the method is not inlined by the compiler.
        protected static ICompileUnitGenerator CreateGenerator(string path)
        {
            AppDomainSetup setup = new AppDomainSetup();
            string[] configFiles = ConfigurationProvider.FindProjectConfigFiles(path);

            setup.ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            setup.ConfigurationFile = configFiles[0]; // Make System.Configuration.ConfigurationManager use this file in the new AppDomain.
            AppDomain domain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, setup);

            return domain.CreateInstanceAndUnwrap(_generatorType.Assembly.FullName, _generatorType.FullName, false, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public, null, new object[] { configFiles }, null, null, null) as ICompileUnitGenerator;
        }

        #endregion Methods


        #region Classes

        /// <summary>
        /// Configuration-wise code generator.
        /// </summary>
        /// <remarks>An instance of this class is not thread safe.</remarks>
        private class CompileUnitGenerator : MarshalByRefObject, ICompileUnitGenerator
        {
            #region Constructors

            /// <summary>
            /// Constructor.
            /// </summary>
            /// <param name="configFiles">The configuration files to use as override.</param>
            public CompileUnitGenerator(string[] configFiles)
            {
                // Use the config files as overrides of the hosting process.
                ConfigurationProvider.CurrentInstance.ConfigFileOverrides = configFiles;

                // Hack to support relative path for code templates.
                // Only support current directory relativity (starting with "." or ".\").
                DataService.LoadProviders(); // This is where SubSonic init its configuration... load it now.
                if (!string.IsNullOrEmpty(SubSonicConfig.TemplateDirectory) && (SubSonicConfig.TemplateDirectory == "." || SubSonicConfig.TemplateDirectory.StartsWith(@".\")))
                {
                    string directory = Path.GetDirectoryName(ConfigurationProvider.CurrentInstance.ConfigFileOverrides[0]);
                    if (!directory.EndsWith(Path.DirectorySeparatorChar.ToString()))
                        directory += Path.DirectorySeparatorChar;
                    if (SubSonicConfig.TemplateDirectory == ".")
                        SubSonicConfig.TemplateDirectory = directory;
                    else
                        SubSonicConfig.TemplateDirectory = directory + SubSonicConfig.TemplateDirectory.Substring(2);
                }
            }

            #endregion Constructors


            #region Methods

            /// <summary>
            /// Generates the DAL in a single CodeCompileUnit from an input file.
            /// </summary>
            /// <param name="languageType">The language to generate the DAL for.</param>
            /// <param name="inputFile">The path to the input file.</param>
            /// <returns>A single CodeCompileUnit.</returns>
            public CodeCompileUnit GenerateSingleUnit(LanguageType languageType, string inputFile)
            {
                BuildProvider builder = new BuildProvider();
                string tableText = Utility.GetFileText(inputFile);

                return builder.GenerateSingleUnit(languageType, tableText);
            }

            /// <summary>
            /// Generates the DAL in multiple CodeCompileUnits for specific tables, views
            /// and, optionnaly, all stored procedures.
            /// </summary>
            /// <param name="languageType">The language to generate the DAL for.</param>
            /// <param name="tables">
            /// The list of tables to generate the DAL for; first element as "*" for all tables.
            /// Can be null or empty. A null value generates no table and no table struct. 
            /// <param name="views">
            /// The list of views to generate the DAL for; first element as "*" for all views.
            /// Can be null or empty. A null value generates no view and no view struct. 
            /// </param>
            /// <param name="useSPs">
            /// true to generate the Stored Procedure; false not to generate.
            /// A null value generates Stored Procedures based on the configuration file option.
            /// </param>
            /// <param name="providerName">
            /// The name of the provider to generate the DAL for.
            /// If null, generates code for all the providers.
            /// </param>
            /// <returns>A dictionary of suggested filenames/CodeCompileUnit pairs.</returns>
            public IDictionary<string, CodeCompileUnit> GenerateMultipleUnits(LanguageType languageType, string[] tables, string[] views, bool? useSPs, string providerName)
            {
                BuildProvider builder = new BuildProvider();
                return builder.GenerateMultipleUnits(languageType, tables, views, useSPs, providerName);
            }

            /// <summary>
            /// Generates the DAL in multiple CodeCompileUnits from an input file.
            /// </summary>
            /// <param name="languageType">The language to generate the DAL for.</param>
            /// <param name="inputFile">The path to the input file.</param>
            /// <returns>A dictionary of suggested filenames/CodeCompileUnit pairs.</returns>
            public IDictionary<string, CodeCompileUnit> GenerateMultipleUnits(LanguageType languageType, string inputFile)
            {
                string tableText = Utility.GetFileText(inputFile);
                string[] tables = tableText.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                string[] views = new string[] { "*" };

                // Use input file for tables; always generate views; generate SP based on config file.
                return GenerateMultipleUnits(languageType, tables, views, null, null);
            }

            /// <summary>
            /// Gets the list of tables.
            /// </summary>
            /// <param name="providerName">
            /// The name of the provider to get the tables for.
            /// If null, uses the default provider.
            /// </param>
            /// <returns>A list of table names.</returns>
            public string[] GetTableNames(string providerName)
            {
                //if (String.IsNullOrEmpty(providerName))
                //    return DataService.GetTableNames(providerName);
                //else
                    return DataService.GetTableNames(providerName);
            }

            /// <summary>
            /// Gets the list of views.
            /// </summary>
            /// <param name="providerName">
            /// The name of the provider to get the views for.
            /// If null, uses the default provider.
            /// </param>
            /// <returns>A list of view names.</returns>
            public string[] GetViewNames(string providerName)
            {
                //if (String.IsNullOrEmpty(providerName))
                //    return DataService.GetViewNames();
                //else
                    return DataService.GetViewNames(providerName);
            }

            /// <summary>
            /// Gets the list of provider names for the current application context.
            /// </summary>
            /// <returns>A list of provider names.</returns>
            public string[] GetProviderNames()
            {
                List<string> providerNames = new List<string>();
                foreach(DataProvider provider in DataService.Providers)
                    providerNames.Add(provider.Name);
                return providerNames.ToArray();
            }

            #endregion Methods
        }

        #endregion Classes
    }
}

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