ASP.NET 2.0 and MCMS – Try it out – Now even in Authoring Mode!

In my previous article I explained what to do to get a read-only MCMS website working on ASP.NET 2.0. In this article I will go one step further and explain how to get a read-write MCMS website working with ASP.NET 2.0!

First of all you need to ensure that all steps in my previous article are done. After you have ensured that the website works correct as a read-only website follow the rest of this article.

ASP.NET 2.0 creates different html code which is incompatible with the javascript code used by WebAuthor. After playing around for a while with a HttpModule and some web.config settings I finally managed resolve all problems.

To successfully run MCMS 2002 on ASP.NET 2.0 the following http module needs to be added to the web.config:

This http module does two things: it corrects the form tag generated by ASP.NET 2.0 and ensures that it is compatible with the javascript code of MCMS and it replaces some of the javascript code generated by the web author console.

using System;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using Microsoft.ContentManagement.Publishing;
using Microsoft.ContentManagement.WebControls;

namespace StefanG.ASPNET20_HttpModule
{

    public class ASPNET20_Filter : Stream 
    {
        private Encoding enc = null;
        private bool closed;
        Stream BaseStream;

        public ASPNET20_Filter(Stream baseStream, Encoding encoding)
        {
            BaseStream = baseStream;
            closed = false;
            enc = encoding;
        }
        
        public override void Write(byte[] buffer, int offset, int count) 
        {

            if(Closed) throw new ObjectDisposedException(“ASPNET20_Filter”);

            string content = enc.GetString(buffer,offset,count);
            byte[] newBuffer = enc.GetBytes(content);
            int pos = content.IndexOf(“<form “);
            while (pos >= 0)
            {
                int endpos = content.IndexOf(“>”,pos);
                int namepos = content.IndexOf(“name=”,pos);
                int idpos = content.IndexOf(“id=”,pos);

                // only modify content if name attribute is not present
                if (namepos == –1 || namepos > endpos)
                {
                    pos = idpos+“id=\””.Length;
                    endpos = content.IndexOf(“\””,pos);
                    if (endpos > 0)
                    {
                        string idString = content.Substring(pos,endpos-pos);

                        // add a name attribute with the same value as the ID attribute
                        content = content.Insert(idpos,“name=\””+idString+“\” “);

                        newBuffer = enc.GetBytes(content);
                        break;
                    }
                }
                pos = content.IndexOf(“<form”,pos+1);
            }
            count = newBuffer.Length;
            BaseStream.Write(newBuffer, 0, count);
        }

        public override bool CanRead
        {    
            get { return false; }
        }

        public override bool CanWrite 
        {
            get { return !closed; }
        }

        public override bool CanSeek 
        {
            get { return false; }
        }

        public override void Close() 
        {
            closed = true;
            BaseStream.Close();
        }

        protected bool Closed 
        {
            get { return closed; }
        }

        public override void Flush() 
        {
            BaseStream.Flush();
        }

        public override int Read(byte[] buffer, int offset, int count) 
        {
            throw new NotSupportedException();
        }

        public override long Length 
        {
            get { throw new NotSupportedException(); }
        }

        public override long Seek(long offset, SeekOrigin origin) 
        {
            throw new NotSupportedException();
        }

        public override void SetLength(long value) 
        {
            throw new NotSupportedException();
        }

        public override long Position 
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }
    } 

    public class ForceMCMScompatibility : IHttpModule 
    {
        public void Init(HttpApplication httpApp) 
        {
            httpApp.PreRequestHandlerExecute += new EventHandler(this.OnPreRequestHandlerExecute);
        }

        public void Dispose() 
        {
            // Nothing to do.
        }

        public void OnPreRequestHandlerExecute(object sender, EventArgs e) 
        {
            HttpContext ctx = ((HttpApplication)sender).Context;
            IHttpHandler handler = ctx.Handler;

            try
            {
                // only take action if we are inside a channel item
                if (CmsHttpContext.Current.ChannelItem != null)
                {
                    // register http filter for
 ASPNET 2.0 compatibility

                    ASPNET20_Filter aspnet20_filter = new ASPNET20_Filter(ctx.Response.Filter, ctx.Response.ContentEncoding);
                    ctx.Response.Filter = aspnet20_filter;
                }
            
                if ((CmsHttpContext.Current.Posting != null) && 
                    ((WebAuthorContext.Current.Mode == WebAuthorContextMode.AuthoringNew) |
                     (WebAuthorContext.Current.Mode == WebAuthorContextMode.AuthoringReedit))) 
                    ((System.Web.UI.Page)handler).Init += new EventHandler(    this.OnInit );
            }
            catch
            {
                // this will happen if the request is in the middle of an expired forms authentication login
                // we just ignore this.
            }
        }

        private const string overrideASPXPostback =
            “\n” +
            “<!– Updated by ASP.NET compliancy module –>\n” +
            “<!– Generated by Microsoft.ContentManagement.WebControls.Console –>\n” +
            “<SCRIPT language=\”javascript\” type=\”text/javascript\”>\n” +
            “<!–\n” +
            ”   var __consoleCachedOriginalPostBack;\n” +
            “\n” +
            ”   if( eval(\”window.__doPostBack\”) != null )\n” +
            ”   {\n” +
            ”       __consoleCachedOriginalPostBack = __doPostBack;\n” +
            ”       __doPostBack = __consoleCustomDoPostBack;\n” +
            ”   }\n” +
            “\n” +
            ”   __consoleCachedOriginalOnSubmit = __CMS_PostbackForm.onsubmit;\n” +
            ”   __CMS_PostbackForm.onsubmit = __consoleHandleOnSubmit;\n” +
            “\n” +
            ”   function __consoleCustomDoPostBack( eventTarget, eventArgument )\n” +
            ”   {\n” +
            ”       WBC_offWarningBeforeLeave();\n” +
            ”       __consoleCachedOriginalPostBack( eventTarget, eventArgument );\n” +
            ”   }\n” +
            “\n” +
            ”   function __consoleHandleOnSubmit()\n” +
            ”   {\n” +
            ”       WBC_offWarningBeforeLeave();\n” +
            ”       if (__consoleCachedOriginalOnSubmit != null)\n” +
            ”       {\n” +
            ”           return __consoleCachedOriginalOnSubmit();\n” +
            ”       }\n” +
            ”        return true;\n” +
            ”   }\n” +
            “// –>\n” +
            “</SCRIPT>\n\n\n”;

        public void OnInit(object sender, EventArgs eventArgs)
        {
            System.Web.UI.Page currentPage = sender as System.Web.UI.Page; 

            // now lets register our script to correct the missing return value
            currentPage.RegisterStartupScript(“OverrideASPXPostback”, overrideASPXPostback); 
        } 
    }
}

In addition it is required to add an additional property to the following line in the web.config

   <pages validateRequest=”false“/>

It now needs to read as follows:

   <pages enableEventValidation=”false” validateRequest=”false“/>

Important: You should not yet use ASP.NET 2.0 on a production site! ASP.NET 2.0 is not supported by Microsoft without MCMS SP2 installed. The steps above should only be used to evaluate the benefits of ASP.NET 2.0 for a MCMS site now. There is also no guarantee that code developed now for a site as configured above will run without changes after SP2 has been installed!

5 Comments


  1. Dear Stefan

    I am having difficulties to get the "Create Page" and "Resource Manager" dialogues to work on my new ASP.NET 2.0 templates

    I get a "Object not set to an instance.." errors.

    Have you successfully gotten these dialogues to work?

    Reply

  2. I found out myself, the "View as list" and "View as tree" listitems were declared at protected members but they were not tagged with runat=server.

    Apparently that vas vaild in .NET 1.1 because they were child object of the DropDownList, but not in 2.0.

    Just maske the following two classes, and make the ResourceGalleriesGrid.ascx and TemplateGalleriesBrowse.aspx enherit from them instead.

    public class ResourceGalleriesGrid : Microsoft.ContentManagement.WebAuthor.ResourceGalleriesGrid

    {

    protected override void OnInit(EventArgs e)

    {

    base.ViewAsList = GalleriesViewSelect.Items[0];

    base.ViewAsTree = GalleriesViewSelect.Items[1];

    base.OnInit(e);

    }

    }

    public class TemplateGalleriesBrowse : Microsoft.ContentManagement.WebAuthor.TemplateGalleriesBrowse

    {

    protected override void OnInit(EventArgs e)

    {

    base.ViewAsList = GalleriesViewSelect.Items[0];

    base.ViewAsTree = GalleriesViewSelect.Items[1];

    base.OnInit(e);

    }

    }

    Reply

  3. So how is this http module added to the config file? Can you post the line I need to make this work?

    Reply

  4. Here is the line that needs to be added:

    <add type="StefanG.ASPNET20_HttpModule.ForceMCMScompatibility, ASPNET20_HttpModule" name="ForceMCMScompatibility"/>

    Reply

  5. As some of you already noticed: GotDotNet is now down and the code samples previously hosted there have

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.