Click here to Skip to main content
15,891,184 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.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Collections;
using System.CodeDom;
using SubSonic.CodeGenerator;
using System.Text.RegularExpressions;
using System.IO;
using SubSonic.Utilities;
using System.Collections.Specialized;

namespace SubSonic
{
    public static class CodeService
    {

        #region Helpers
        private static string templateDirectory = string.Empty;
        public static string TemplateDirectory
        {
            get { return templateDirectory; }
            set { templateDirectory = value; }
        }
        public enum TemplateType
        {
            Class,
            ODSController,
            ReadOnly,
            SP,
            Structs,
            DynamicScaffold,
            GeneratedScaffoldCodeBehind,
            GeneratedScaffoldMarkup
        }

        public enum ReplacementVariable
        {
            Table,
            Provider,
            View,
            StoredProcedure
        }
        public class Replacement
        {
            public Replacement(ReplacementVariable variable, string replace)
            {
                Variable = variable;
                ReplaceWith = replace;
            }

            private ReplacementVariable replaceVar;
            public ReplacementVariable Variable
            {
                get { return replaceVar; }
                set { replaceVar = value; }
            }


            private string replaceWith;
            public string ReplaceWith
            {
                get { return replaceWith; }
                set { replaceWith = value; }
            }

        }

        #endregion

        /// <summary>
        /// Not currently used, but will be the basis for user defined templates. Please don't remove!
        /// </summary>
        /// <param name="templateFile"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static string RunTemplate(string templateFile, NameValueCollection values)
        {
            string result;
            string templatePath = Path.Combine(TemplateDirectory, templateFile);
            string templateText = Sugar.Files.GetFileText(templatePath);

            for (int i = 0; i < values.Count; i++)
            {
                templateText = templateText.Replace(values.GetKey(i), values.Get(i));
            }

            Template t = new Template(templateText);
            result = t.Render();

            if (String.IsNullOrEmpty(result))
                throw new Exception("There is no code generated. Houston, we have a problem! Check to make sure there is a primary key defined. " +
                    "Also, this could be a  naming issue. " +
                    "Check that your columns do not contain reserved words or punctuation/numbers. Also make sure that no columns have " +
                    "the same name as their containing table." + Environment.NewLine + t.Error);

            //must run AFTER Template.Render()
            result = ScrubOutput(result);

            if (String.IsNullOrEmpty(result))
            {
                throw new Exception(templateFile + ": " + t.Error);
            }
            return result;
        }

        public static string RunTemplate(TemplateType templateType, NameValueCollection values, ICodeLanguage language)
        {
            string result;
            string templateText = GetTemplateText(templateType, language);

            for (int i = 0; i < values.Count; i++)
            {
                templateText = templateText.Replace(values.GetKey(i), values.Get(i));
            }

            Template t = new Template(templateText);
            t.Language = language;

            Utility.WriteTrace("Rendering template");
            result = t.Render();

            if (!String.IsNullOrEmpty(result))
            {
                Utility.WriteTrace("Fixing output...");
                result = ScrubOutput(result);
                Utility.WriteTrace("Finished :)");
            }
            return result;
        }

        static string RunTemplate(TemplateType templateType, List<Replacement> settings, ICodeLanguage language)
        {

            Utility.WriteTrace("Getting Template");
            string templateText = GetTemplateText(templateType, language);

            //set the provider and tablename
            Utility.WriteTrace("Replacing values in template");
            foreach (Replacement var in settings)
            {
                string replaceHolder = "#" + Enum.GetName(typeof(ReplacementVariable), var.Variable).ToUpper() + "#";
                templateText = Utility.FastReplace(templateText, replaceHolder, var.ReplaceWith, StringComparison.InvariantCultureIgnoreCase);
                //templateText = templateText.Replace(replaceHolder, var.ReplaceWith);
            }



            string result;
            Template t = new Template(templateText);
            t.Language = language;

            Utility.WriteTrace("Rendering template");
            result = t.Render();

            if (!String.IsNullOrEmpty(result))
            {
                Utility.WriteTrace("Fixing output...");
                result = ScrubOutput(result);
                Utility.WriteTrace("Finished :)");
            }

            return result;

        }

        public static bool ShouldGenerate(string objectName, string[] includeList, string[] excludeList, DataProvider provider)
        {
            bool result = true;
            bool generateAll = false;

            //first, check to see if the includeList says to include all tables
            //this is a default
            if (includeList.Length == 1)
            {
                if (includeList[0] == "*")
                {
                    generateAll = true;
                }
            }

            //if we need to generate all tables, then we need to check the excludeList
            if (generateAll)
            {
                foreach (string s in excludeList)
                {
                    if (Utility.IsRegexMatch(objectName, s.Trim()))
                    {
                        result = false;
                        break;
                    }
                }
            }
            else
            {
                //IncludeList TRUMPs excludeList in case of confusion
                //what this means is that if there is an includeList,
                //be definition there's an excludeList of all tables not included
                //yep, confusing.

                //this means that tables were specifically requested in the includeList
                //need to make them prove themselves
                result = false;

                foreach (string s in includeList)
                {
                    if (Utility.IsRegexMatch(objectName, s.Trim()))
                    {
                        result = true;
                        break;
                    }
                }
            }

            return result;
        }

        public static bool ShouldGenerate(TableSchema.Table tbl)
        {
            return ShouldGenerate(tbl.TableName, tbl.Provider.Name);
        }

        public static bool ShouldGenerate(string tableName, string providerName)
        {
            DataProvider provider = DataService.Providers[providerName];
            if (provider == null)
                throw new Exception("There is no provider with the name " + providerName);

            return ShouldGenerate(tableName, provider.IncludeTables, provider.ExcludeTables, provider);
        }

        public static string RunODS(string tableName, string providerName, ICodeLanguage language)
        {
            //make sure the providers are loaded
            DataService.LoadProviders();


            string result = string.Empty;
            if (ShouldGenerate(tableName, providerName) && DataService.Providers[providerName].GenerateODSControllers)
            {
                Utility.WriteTrace("####### Creating ODS Controller for " + tableName + " ####### ");
                List<Replacement> list = new List<Replacement>();
                list.Add(new Replacement(ReplacementVariable.Table, tableName));
                list.Add(new Replacement(ReplacementVariable.Provider, providerName));

                result = RunTemplate(TemplateType.ODSController, list, language);
            }
            else
            {
                Utility.WriteTrace(tableName + " is Excluded from generation");
            }
            return result;
        }


        public static string RunClass(string tableName, string providerName, ICodeLanguage language)
        {
            //make sure the providers are loaded
            DataService.LoadProviders();

            string result = string.Empty;
            if (ShouldGenerate(tableName, providerName))
            {

                Utility.WriteTrace("####### Creating class for " + tableName + " ####### ");
                List<Replacement> list = new List<Replacement>();
                list.Add(new Replacement(ReplacementVariable.Table, tableName));
                list.Add(new Replacement(ReplacementVariable.Provider, providerName));

                result = RunTemplate(TemplateType.Class, list, language);
            }
            else
            {
                Utility.WriteTrace(tableName + " is Excluded from generation");

            }
            return result;
        }


        public static string RunReadOnly(string viewName, string providerName, ICodeLanguage language)
        {
            //make sure the providers are loaded
            DataService.LoadProviders();

            string result = string.Empty;
            if (ShouldGenerate(viewName, providerName))
            {
                Utility.WriteTrace("####### Creating ReadOnly class for View " + viewName + " ####### ");
                List<Replacement> list = new List<Replacement>();
                list.Add(new Replacement(ReplacementVariable.View, viewName));
                list.Add(new Replacement(ReplacementVariable.Provider, providerName));

                result = RunTemplate(TemplateType.ReadOnly, list, language);
            }
            else
            {
                Utility.WriteTrace(viewName + " is Excluded from generation");

            }
            return result;


        }
        public static string RunSPs(string providerName, ICodeLanguage language)
        {
            //make sure the providers are loaded
            DataService.LoadProviders();

            Utility.WriteTrace("####### Creating SP class ####### ");
            List<Replacement> list = new List<Replacement>();
            list.Add(new Replacement(ReplacementVariable.Provider, providerName));

            return RunTemplate(TemplateType.SP, list, language);


        }
        public static string RunStructs(ICodeLanguage language)
        {

            //make sure the providers are loaded
            DataService.LoadProviders();

            Utility.WriteTrace("####### Creating Structs ####### ");
            List<Replacement> list = new List<Replacement>();
            return RunTemplate(TemplateType.Structs, list, language);


        }

        static string ScrubOutput(string sIn)
        {
            string result = sIn;

            if (!String.IsNullOrEmpty(result))
            {
                //the generator has an issue with adding extra lines. Trim them out
                Regex reg = new Regex(@"[\r\n]+");
                result = reg.Replace(result, "\r\n");

                //now, for readability, add a space after the end of the method/class
                result = Utility.FastReplace(result, "}", "}\r\n", StringComparison.InvariantCultureIgnoreCase);
                result = Utility.FastReplace(result, "namespace", "\r\nnamespace", StringComparison.InvariantCulture); //Must be case-sensitive, or it will cause VB End Namespace to wrap

                //these must remain as two separate procedures, or bad things will happen in VB
                result = Utility.FastReplace(result, "public class ", "\r\npublic class ", StringComparison.InvariantCulture); //trailing space need to address class names that begin with "class"
                result = Utility.FastReplace(result, "Public Class ", "\r\nPublic Class ", StringComparison.InvariantCulture); //trailing space need to address class names that begin with "Class"
                result = Utility.FastReplace(result, "[<]", "<", StringComparison.InvariantCultureIgnoreCase);
                result = Utility.FastReplace(result, "[>]", ">", StringComparison.InvariantCultureIgnoreCase);

                //This is should be executed last. While this value will ultimately be removed, it can be inserted in a template to keep an earlier operation from executing.
                //For example: <System.ComponentModel.DataObject()> Public Class MyController would normally wrap to a second line due upstream processing, which would
                //result in VB code that won't compile. However, <System.ComponentModel.DataObject()> Public [MONKEY_WRENCH]Class MyController, would not.

                //Nice Eric... :P
                result = Utility.FastReplace(result, "[MONKEY_WRENCH]", String.Empty, StringComparison.InvariantCultureIgnoreCase);

                return result;
            }
            else
            {
                throw new Exception("There is no code to scrub: " + sIn);
            }
        }

        public static CodeCompileUnit BuildCompilUnit(string code)
        {
            return new CodeSnippetCompileUnit(code);

        }

        static string GetTemplateText(TemplateType t, ICodeLanguage language)
        {
        	string template = language.TemplatePrefix;
            string templateText = null;

            switch (t)
            {
                case TemplateType.Class:
                    template += TemplateName.CLASS;
                    break;
                case TemplateType.ReadOnly:
                    template += TemplateName.VIEW;
                    break;
                case TemplateType.SP:
                    template += TemplateName.STORED_PROCEDURE;
                    break;
                case TemplateType.Structs:
                    template += TemplateName.STRUCTS;
                    break;
                case TemplateType.ODSController:
                    template += TemplateName.ODS_CONTROLLER;
                    break;
                case TemplateType.DynamicScaffold:
                    template += TemplateName.DYNAMIC_SCAFFOLD;
                    break;
                case TemplateType.GeneratedScaffoldCodeBehind:
                    template += TemplateName.GENERATED_SCAFFOLD_CODE_BEHIND;
                    break;
                case TemplateType.GeneratedScaffoldMarkup:
                    template += TemplateName.GENERATED_SCAFFOLD_MARKUP;
                    break;
                default:
                    template += TemplateName.CLASS;
                    break;
            }

        	template += FileExtension.DOT_ASPX;

			//decide where to pull the text from
            if (!String.IsNullOrEmpty(templateDirectory))
            {
                Utility.WriteTrace("Looking for template " + template + " in " + templateDirectory);

                //make sure the template exists
                string templatePath = Path.Combine(templateDirectory, template);

                if (File.Exists(templatePath))
                {
                    //pull the text from there
                    templateText = Sugar.Files.GetFileText(templatePath);
                }
                else
                {
                    Utility.WriteTrace("Template " + template + " NOT FOUND in directory " + templateDirectory + "; using embedded resource template instead...");
                }
            }

            if (String.IsNullOrEmpty(templateText))
            {
                Utility.WriteTrace("Loading template from Resource for " + template);
                templateText = Template.LoadTextFromManifest(template);
            }

            if (String.IsNullOrEmpty(templateText))
                throw new Exception("The template \"" + template + "\" is empty or cannot be found.");

            return templateText;
        }
    }
}

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