The Content Editor Web Part (CEWP) shipped with SharePoint 2007 is just one of these ordinary Web Parts: they don't introduce any extraordinary functionality, yet we all use them in our solutions for some reason. Because this Web Part is all about displaying the Rich Text you have entered, you might think, that it is almost impossible to mess that up. Unfortunately…

The problem about using the Content Editor Web Part is that it makes absolute URL of all the relative ones you have entered. What's the problem? – you might think. Imagine that you have separate editors environment – where the content is being edited, and a public site with anonymous access. If you're not using the Content Deployment the public site is very likely to be an extended version of the editors Web Application. How would you feel if all the links would point to the editors Web Application where you have to login instead of the public one?

For those of you who have worked with the Content Editor Web Part for a while now it's probably nothing new. While in general it wouldn't be particularly difficult to override this behavior, the ContentEditorWebPart is sealed – you cannot extend it nor modify it. While building your own alternative might be an option there is another way to solve this issue using Control Adapters.

Control Adapters have been introduced in the ASP.NET 2.0 framework as an extra layer of logic which can be used to override the way the presentation layer is being rendered. By benefiting of that concept you can create your control once and reuse it in every project you will ever work on by modifying the presentation layer with Control Adapters.

Because the ContentEditorWebPart is sealed you cannot extend it. You are still able though, to create a custom Control Adapter which will apply the required modification. In our case it will make all URLs relative.

The Concept

The idea of the custom Control Adapter for the Content Editor Web Part is very simple: hookup to the Content Editor Web Part, intercept the HTML rendered by the Web Part, turn all absolute URLs into relative and render the output.

ContentEditorWebPartAdapter

public class ContentEditorWebPartAdapter : ControlAdapter
{
  protected override void Render(System.Web.UI.HtmlTextWriter writer)
  {
    StringBuilder sb = new StringBuilder();
    HtmlTextWriter htw = new HtmlTextWriter(new StringWriter(sb));
    base.Render(htw);

    // make all URLs relative
    Regex regex = new Regex(
      "((?:href|src)=\")https?://[^/]+([^\"]+\")");
    string output = regex.Replace(sb.ToString(), "$1$2");

    writer.Write(output);
  }
}

That's really all. First of all you get the rendered output. It's being stored in the sb StringBuilder. Then you make all absolute URLs relative. While you could use the standard String.Replace to improve the overall performance of this routine, I have chosen for the Regular Expressions to make it a bit more safe and reusable. The last step is writing the output back on the page.

Linking the ContentEditorWebPartAdapter to the Content Editor Web Part

The next thing to do is to attach the custom Control Adapter we have just created to the Content Editor Web Part. You do this by creating a .browser (for example Imtech.browsers) file in the App_Browsers directory of your Web Application. This file has to contain the following:

<browsers>
    <browser refID="Default">
        <controlAdapters>
            <adapter
controlType="Microsoft.SharePoint.WebPartPages.ContentEditorWebPart"
adapterType="Imtech.SharePoint.Adapters.ContentEditorWebPartAdapter" />
        </controlAdapters>
    </browser>
</browsers>

The controlType attribute defines the type you want to attach to (Content Editor Web Part in our case) and the adapterType defines the full name of our custom Control Adapter. Since I have deployed it to the bin directory, the full type name is sufficient. On the other hand you might want this to make part of your existing assembly residing in GAC. In such case you have to extend the adapterType definition with the fully qualified name including the Public Key Token.

Wait! We're using SharePoint

In a plain ASP.NET application that would be sufficient. However, since we're using SharePoint you have to apply some modifications to the web.config. You have to allow your custom Control Adapter to access the SharePoint API. To do that you either have to set the trust to Full or create a Code Access Policy. As I know my own code and I definitely trust it, I have chosen for the first approach.

Summary

The Content Editor Web Part is a very convenient control which allows the end users to put on the pages some extra information which doesn't necessary have to be a part of the particular Content Type. In spite of the fact that the CEWP turns all relative URLs into absolute and cannot be extended there are some possibilities to override the default behavior and keep using the Web Part on extended Web Applications. The concept of Control Adapters suits this situation perfectly and is definitely an efficient alternative comparing to creating your own Web Part.