Source code location: ./pipeline/pipeline.aspx.cs

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Web;
using System.Web.UI.WebControls;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

namespace AspNetResources.Web
{
	public class pipeline : PageBase
	{
        private enum TargetLanguage { CSharp, VbNet };

        #region Page controls

	    protected ValidationSummary vs;
	    protected DropDownList drpLanguage;
	    protected TextBox txtNamespace;
	    protected RequiredFieldValidator RequiredNs;
	    protected TextBox txtClassName;
	    protected RequiredFieldValidator RequiredCn;
	    protected DropDownList drpType;
	    protected CheckBoxList chkEventsBefore;
	    protected CheckBoxList chkEventsAfter;
	    protected CheckBoxList chkEventsNd;
	    protected PlaceHolder plhModule;
	    protected RadioButtonList usesession;
	    protected Button btnGenerate;
	    protected TextBox txtTempalte;
	    protected PlaceHolder plhTemplate;
	    protected RadioButtonList brlUseSessionInHandler;
	    protected PlaceHolder plhHandler;

	    #endregion
    
        #region Events
        private void TargetTypeChanged (object sender, EventArgs e)
        {
            plhModule.Visible = (drpType.SelectedIndex == 0);
            plhHandler.Visible = (drpType.SelectedIndex == 1);
        }

        private void GenerateTemplate (object sender, EventArgs e)
        {
            if (!Page.IsValid)
                return;

            CodeCompileUnit     graph = null;
            TargetLanguage      language = TargetLanguage.CSharp;

            switch (drpLanguage.SelectedIndex)
            {
                case 0: language = TargetLanguage.CSharp; break;
                case 1: language = TargetLanguage.VbNet; break;
            }

            switch (drpType.SelectedIndex)
            {
                case 0: graph = GenerateModuleTemplate (language); break;
                case 1: graph = GenerateHandlerTemplate (language); break;
                case 2: graph = GenerateFactoryTemplate (language); break;
            }

            // --------------------------------------------------
            // Generate code from the graph
            // --------------------------------------------------
            CodeDomProvider provider = null;

            switch (language)
            {
                case TargetLanguage.CSharp: provider = new CSharpCodeProvider (); break;
                case TargetLanguage.VbNet:  provider = new VBCodeProvider (); break;
            }

            // Obtain an ICodeGenerator from the CodeDomProvider class.
            ICodeGenerator          gen = provider.CreateGenerator();

            // Create the strem where generated code is to be written
            StringWriter            swr = new StringWriter ();
            IndentedTextWriter      itw = new IndentedTextWriter (swr);

            gen.GenerateCodeFromCompileUnit (graph, itw, new CodeGeneratorOptions ());
            itw.Close ();

            plhTemplate.Visible = true;
            txtTempalte.Text = swr.ToString ();
        }
        #endregion

        #region Code-generation helpers
        private CodeCompileUnit GenerateFactoryTemplate (TargetLanguage language)
        {
            // --------------------------------------------------
            // First, build a DOM graph
            // --------------------------------------------------
            CodeCompileUnit                 compileUnit = new CodeCompileUnit ();
            CodeNamespace                   ns = new CodeNamespace (txtNamespace.Text.Trim());
            CodeNamespaceImport[]           imports = { new CodeNamespaceImport ("System"), new CodeNamespaceImport ("System.Web") };
            CodeTypeDeclaration             cls = new CodeTypeDeclaration (txtClassName.Text.Trim ());

            compileUnit.Namespaces.Add      (ns);
            ns.Imports.AddRange             (imports);
            ns.Types.Add                    (cls);


            switch (language)
            {
                case TargetLanguage.CSharp: cls.BaseTypes.Add ("IHttpHandlerFactory"); break;
                case TargetLanguage.VbNet:  cls.Members.Add (new CodeSnippetTypeMember("Implements IHttpHandlerFactory")); break;
            }
            
            // --------------------------------------------------
            // Generate:
            // public void ReleaseHandler(IHttpHandler handler)
            // --------------------------------------------------
            CodeMemberMethod releaseHandlerMethod = new CodeMemberMethod ();
            releaseHandlerMethod.Name = "ReleaseHandler";
            releaseHandlerMethod.Attributes = MemberAttributes.Final | MemberAttributes.Public;
            releaseHandlerMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (IHttpHandler), "handler"));
            releaseHandlerMethod.ImplementationTypes.Add (new CodeTypeReference("IHttpHandlerFactory"));

            cls.Members.Add (releaseHandlerMethod);

            // --------------------------------------------------
            // Generate:
            // public bool IsReusable
            // --------------------------------------------------
            CodeMemberProperty isReusableProp = new CodeMemberProperty ();
            isReusableProp.Name = "IsReusable";
            isReusableProp.Attributes = MemberAttributes.Final | MemberAttributes.Public;
            isReusableProp.HasGet = true;
            isReusableProp.HasSet = false;
            isReusableProp.Type = new CodeTypeReference (typeof (bool));

            isReusableProp.GetStatements.Add (new CodeCommentStatement ("To enable pooling, return true here."));
            isReusableProp.GetStatements.Add (new CodeCommentStatement ("This keeps the handler in memory."));
            isReusableProp.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (true)));

            cls.Members.Add (isReusableProp);

            // --------------------------------------------------
            // Generate:
            //public IHttpHandler GetHandler(HttpContext context, string requestType, String url, String pathTranslated)
            // --------------------------------------------------
            CodeMemberMethod getHandlerMethod = new CodeMemberMethod ();
            getHandlerMethod.Name = "GetHandler";
            getHandlerMethod.Attributes = MemberAttributes.Final | MemberAttributes.Public;
            getHandlerMethod.ReturnType = new CodeTypeReference (typeof (IHttpHandler));
            getHandlerMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (HttpContext), "context"));
            getHandlerMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (string), "requestType"));
            getHandlerMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (string), "url"));
            getHandlerMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (string), "pathTranslated"));

            CodeVariableDeclarationStatement handlerToReturn = new CodeVariableDeclarationStatement (typeof (IHttpHandler), "handlerToReturn", new CodePrimitiveExpression (null));
            getHandlerMethod.Statements.Add (handlerToReturn);
            getHandlerMethod.Statements.Add (new CodeMethodReturnStatement (new CodeVariableReferenceExpression ("handlerToReturn")));

            getHandlerMethod.ImplementationTypes.Add (new CodeTypeReference("IHttpHandlerFactory"));
            cls.Members.Add (getHandlerMethod);
            
            return compileUnit;
        }

        private CodeCompileUnit GenerateHandlerTemplate (TargetLanguage language)
        {
            // --------------------------------------------------
            // First, build a DOM graph
            // --------------------------------------------------
            CodeCompileUnit                 compileUnit = new CodeCompileUnit ();
            CodeNamespace                   ns = new CodeNamespace (txtNamespace.Text.Trim());
            CodeNamespaceImport[]           imports = { new CodeNamespaceImport ("System"), new CodeNamespaceImport ("System.Web") };
            CodeTypeDeclaration             cls = new CodeTypeDeclaration (txtClassName.Text.Trim ());

            compileUnit.Namespaces.Add      (ns);
            ns.Imports.AddRange             (imports);
            ns.Types.Add                    (cls);


            if (brlUseSessionInHandler.SelectedIndex == 0)
                ns.Imports.Add (new CodeNamespaceImport ("System.Web.SessionState"));

            switch (language)
            {
                case TargetLanguage.CSharp: cls.BaseTypes.Add ("IHttpHandler"); break;
                case TargetLanguage.VbNet:  cls.Members.Add (new CodeSnippetTypeMember("Implements IHttpHandler")); break;
            }

            if (brlUseSessionInHandler.SelectedIndex == 0)
                cls.BaseTypes.Add ("IRequiresSessionState");
            
            // --------------------------------------------------
            // Generate:
            // public void ProcessRequest (HttpContext context)
            // --------------------------------------------------
            CodeMemberMethod procRequestMethod = new CodeMemberMethod ();
            procRequestMethod.Name = "ProcessRequest";
            procRequestMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            procRequestMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (HttpContext), "context"));
            procRequestMethod.ImplementationTypes.Add (new CodeTypeReference("IHttpHandler"));

            cls.Members.Add (procRequestMethod);

            // --------------------------------------------------
            // Generate:
            // public bool IsReusable
            // --------------------------------------------------
            CodeMemberProperty isReusableProp = new CodeMemberProperty ();
            isReusableProp.Name = "IsReusable";
            isReusableProp.HasGet = true;
            isReusableProp.HasSet = false;
            isReusableProp.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            isReusableProp.Type = new CodeTypeReference (typeof (bool));

            isReusableProp.GetStatements.Add (new CodeCommentStatement ("To enable pooling, return true here."));
            isReusableProp.GetStatements.Add (new CodeCommentStatement ("This keeps the handler in memory."));
            isReusableProp.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (true)));

            isReusableProp.ImplementationTypes.Add (new CodeTypeReference("IHttpHandler"));
            cls.Members.Add (isReusableProp);

            return compileUnit;
        }

        private CodeCompileUnit GenerateModuleTemplate (TargetLanguage language)
        {
            // --------------------------------------------------
            // First, build a DOM graph
            // --------------------------------------------------
            CodeCompileUnit                 compileUnit = new CodeCompileUnit ();
            CodeNamespace                   ns = new CodeNamespace (txtNamespace.Text.Trim());
            CodeNamespaceImport[]           imports = { new CodeNamespaceImport ("System"), new CodeNamespaceImport ("System.Web") };
            CodeTypeDeclaration             cls = new CodeTypeDeclaration (txtClassName.Text.Trim ());

            compileUnit.Namespaces.Add      (ns);
            ns.Imports.AddRange             (imports);
            ns.Types.Add                    (cls);


            switch (language)
            {
                case TargetLanguage.CSharp: cls.BaseTypes.Add ("IHttpModule"); break;
                case TargetLanguage.VbNet:  cls.Members.Add (new CodeSnippetTypeMember("Implements IHttpModule")); break;
            }

            // --------------------------------------------------
            // Generate:
            // public void Init (HttpApplication application)
            // --------------------------------------------------
            CodeMemberMethod initMethod = new CodeMemberMethod ();
            initMethod.Name = "Init";
            initMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            initMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (HttpApplication), "application"));
            initMethod.Comments.Add (new CodeCommentStatement ("In the Init method register for HttpApplication events by adding your handlers", true));

            initMethod.ImplementationTypes.Add (new CodeTypeReference("IHttpModule"));
            cls.Members.Add (initMethod);

            // --------------------------------------------------
            // Combine all selected events
            // --------------------------------------------------
            CheckBoxList cblSelectedEvents = new CheckBoxList ();

            foreach (ListItem li in chkEventsBefore.Items)
            {
                if (li.Selected)
                    cblSelectedEvents.Items.Add (li);
            }

            foreach (ListItem li in chkEventsAfter.Items)
            {
                if (li.Selected)
                    cblSelectedEvents.Items.Add (li);
            }

            foreach (ListItem li in chkEventsNd.Items)
            {
                if (li.Selected)
                    cblSelectedEvents.Items.Add (li);
            }


            // We need to go through all checked events and wire each one a delegate
            foreach (ListItem li in cblSelectedEvents.Items)
            {
                if (!li.Selected)
                    continue;

                string evt = li.Value;

                CodeDelegateCreateExpression evtDelegate = new CodeDelegateCreateExpression (
                    new CodeTypeReference ("EventHandler"), new CodeThisReferenceExpression (), string.Concat ("Application_", evt));

                CodeAttachEventStatement evtAttach = new CodeAttachEventStatement (
                    new CodeArgumentReferenceExpression ("application"), evt, evtDelegate);

                initMethod.Statements.Add (evtAttach);

                // ---------------------------
                // Add a corresponding method
                // ---------------------------
                CodeMemberMethod evtMethod = new CodeMemberMethod ();
                evtMethod.Name = string.Concat ("Application_", evt);
                evtMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
                evtMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));

                //evtMethod.Statements.Add (new CodeCommentStatement ("HttpApplication app = (HttpApplication) sender;"));
                //evtMethod.Statements.Add (new CodeCommentStatement ("HttpContext context = app.Context;"));
                CodeVariableDeclarationStatement loc1 = new CodeVariableDeclarationStatement (
                    "HttpApplication", "app", new CodeCastExpression ("HttpApplication", new CodeArgumentReferenceExpression ("sender")));
                evtMethod.Statements.Add (loc1);

                CodeVariableDeclarationStatement loc2 = new CodeVariableDeclarationStatement (
                    "HttpContext", "context", new CodePropertyReferenceExpression (new CodeVariableReferenceExpression ("app"), "Context"));
                evtMethod.Statements.Add (loc2);

                cls.Members.Add (evtMethod);
            }

            // --------------------------------------------------
            // Generate:
            // public void Dispose ()
            // --------------------------------------------------
            CodeMemberMethod disposeMethod = new CodeMemberMethod ();
            disposeMethod.Name = "Dispose";
            disposeMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;

            disposeMethod.ImplementationTypes.Add (new CodeTypeReference("IHttpModule"));
            cls.Members.Add (disposeMethod);

            return compileUnit;
        }
        #endregion

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			base.OnInit(e);

            drpType.SelectedIndexChanged += new EventHandler (TargetTypeChanged);
            btnGenerate.Click += new EventHandler (GenerateTemplate);
		}
		#endregion
	}
}