0

I have an aspx page that contains regular html, some uicomponents, and multiple tokens of the form {tokenname} .

When the page loads, I want to parse the page content and replace these tokens with the correct content. The idea is that there will be multiple template pages using the same codebehind.

I've no trouble parsing the string data itself, (see named string formatting, replace tokens in template) my trouble lies in when to read, and how to write the data back to the page...

What's the best way for me to rewrite the page content? I've been using a streamreader, and the replacing the page with Response.Write, but this is no good - a page containing other .net components does not render correctly.

Any suggestions would be greatly appreciated!

Community
  • 1
  • 1
RYFN
  • 2,939
  • 1
  • 29
  • 40

3 Answers3

1

Take a look at System.Web.UI.Adapters.PageAdapter method TransformText - generally it is used for multi device support, but you can postprocess your page with this.

Dewfy
  • 23,277
  • 13
  • 73
  • 121
1

I'm not sure if I'm answering your question, but... If you can change your notation from

{tokenname}

to something like

<%$ ZeusExpression:tokenname %>

you could consider creating your System.Web.Compilation.ExpressionBuilder.

After reading your comment...

There are other ways of getting access to the current page using ExpressionBuilder: just... create an expression. ;-) Changing just a bit the sample from MSDN and supposing the code of your pages contain a method like this

public object GetData(string token);

you could implement something like this

public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
    Type type1 = entry.DeclaringType;
    PropertyDescriptor descriptor1 = TypeDescriptor.GetProperties(type1)[entry.PropertyInfo.Name];
    CodeExpression[] expressionArray1 = new CodeExpression[1];
    expressionArray1[0] = new CodePrimitiveExpression(entry.Expression.Trim());

    return new CodeCastExpression(
        descriptor1.PropertyType,
        new CodeMethodInvokeExpression(
            new CodeThisReferenceExpression(),
            "GetData",
            expressionArray1));
}

This replaces your placeholder with a call like this

(string)this.GetData("tokenname");

Of course you can elaborate much more on this, perhaps using a "utility method" to simplify and "protect" access to data (access to properties, no special method involved, error handling, etc.).

Something that replaces instead with (e.g.)

(string)Utilities.GetData(this, "tokenname");

Hope this helps.

Fabrizio C.
  • 1,544
  • 10
  • 12
  • That's quite an interesting solution, thanks for the input :) problem is I need data from my current page in order to render the replacement text - not sure if I can pass things from my current page to the expression builder? I just found a solution actually... perhaps I should answer my own question in case others are wondering – RYFN Aug 12 '09 at 14:57
  • Yes, I agree you should present you own solution. Anyway I edited my proposal to (try to) answer some of your concerns. – Fabrizio C. Aug 17 '09 at 10:55
0

Many thanks to those that contributed to this question, however I ended up using a different solution -

Overriding the render function as per this page, except I parsed the page content for multiple different tags using regular expressions.

protected override void Render(HtmlTextWriter writer)
    {
         if (!Page.IsPostBack)
        {
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(stream))
                {
                    HtmlTextWriter htmlWriter = new HtmlTextWriter(streamWriter);
                    base.Render(htmlWriter);
                    htmlWriter.Flush();
                    stream.Position = 0;
                    using (System.IO.StreamReader oReader = new System.IO.StreamReader(stream))
                    {
                        string pageContent = oReader.ReadToEnd();
                        pageContent = ParseTagsFromPage(pageContent);
                        writer.Write(pageContent);
                        oReader.Close();
                    }
                }
            }
        }
        else
        {
            base.Render(writer);
        }
    }

Here's the regex tag parser

private string ParseTagsFromPage(string pageContent)
    {
        string regexPattern = "{zeus:(.*?)}"; //matches {zeus:anytagname}
        string tagName = "";
        string fieldName = "";
        string replacement = "";
        MatchCollection tagMatches = Regex.Matches(pageContent, regexPattern);
        foreach (Match match in tagMatches)
        {
            tagName = match.ToString();
            fieldName = tagName.Replace("{zeus:", "").Replace("}", "");
            //get data based on my found field name, using some other function call
            replacement = GetFieldValue(fieldName); 
            pageContent = pageContent.Replace(tagName, replacement);
        }
        return pageContent;
    }

Seems to work quite well, as within the GetFieldValue function you can use your field name in any way you wish.

RYFN
  • 2,939
  • 1
  • 29
  • 40