views:

1027

answers:

5

Hello everyone,

I am using VSTS 2008 + C# + .Net 2.0. When executing the following statement, there is FormatException thrown from String.Format statement, any ideas what is wrong?

Here is where to get the template.html I am using. I want to format this part m={0} in template.html.

    string template = String.Empty;
    using (StreamReader textFile = new StreamReader("template.html"))
    {
        template = textFile.ReadToEnd();
        String.Format(template, "video.wmv");
    }

http://www.mediafire.com/download.php?u4myvhbmmzg

EDIT 1:

Here is the content for my template.html,

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml" >
<!-- saved from url=(0014)about:internet -->
<head>
    <title>Silverlight Project Test Page </title>

    <style type="text/css">
    html, body {
        height: 100%;
        overflow: auto;
    }
    body {
        padding: 0;
        margin: 0;
    }
    #silverlightControlHost {
        height: 100%;
    }
    </style>

    <script type="text/javascript">
        function onSilverlightError(sender, args) {

            var appSource = "";
            if (sender != null && sender != 0) {
                appSource = sender.getHost().Source;
            } 
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;

            var errMsg = "Unhandled Error in Silverlight 2 Application " +  appSource + "\n" ;

            errMsg += "Code: "+ iErrorCode + "    \n";
            errMsg += "Category: " + errorType + "       \n";
            errMsg += "Message: " + args.ErrorMessage + "     \n";

            if (errorType == "ParserError")
            {
                errMsg += "File: " + args.xamlFile + "     \n";
                errMsg += "Line: " + args.lineNumber + "     \n";
                errMsg += "Position: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError")
            {           
                if (args.lineNumber != 0)
                {
                    errMsg += "Line: " + args.lineNumber + "     \n";
                    errMsg += "Position: " +  args.charPosition + "     \n";
                }
                errMsg += "MethodName: " + args.methodName + "     \n";
            }

            throw new Error(errMsg);
        }
    </script>
</head>

<body>
    <!-- Runtime errors from Silverlight will be displayed here.
    This will contain debugging information and should be removed or hidden when debugging is completed -->
    <div id='errorLocation' style="font-size: small;color: Gray;"></div>

    <div id="silverlightControlHost">
     <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="500" height="240">
      <param name="source" value="ClientBin/VideoPlayer.xap"/>
      <param name="onerror" value="onSilverlightError" />
      <param name="background" value="white" />
      <param name="initParams" value="cc=true,markers=true,m={0}" />
      <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
          <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
      </a>
     </object>
     <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
    </div>
</body>
</html>

thanks in avdance, George

+20  A: 

At a guess, the html contains javascript or another source of braces ({ and }) which would all need doubling (to {{ and }}) to be usable with string.Format. I expect a different (more obvious) token may be in order, i.e. %%FILENAME%%. Then use either regex or string.Replace.

If you have a single tag, string.Replace is fine; if you have lots, there are tricks with regex and MatchEvaluator that may be helpful - like so but with a different regex pattern.


Update after the example html added: I would definitely use a different token; at the most basic level:

<param name="initParams" value="cc=true,markers=true,m=%%FILENAME%%" />

and

template = template.Replace("%%FILENAME%%", "video.wmv");
Marc Gravell
I second this check for other curly brackets.
Omar Kooheji
Cool, Marc, I like your smart solution.
George2
Marc, could you explain what do you mean "would all need doubling (to {{ and }}) to be usable with string.Format", I am confused what means need doubling to be usable with string.Format.
George2
If the brace isn't part of a replacement token (i.e. it isn't {0}), then that brace needs to be doubled to that string.Format understands what you mean. i.e. string.Format("this {{ is {0} a }} test", 6) should return "this { is 6 a } test". When it sees a {{ or }} it replaces it with a single { or } in the result, and **doesn't** attempt to treat it as a token like {0}, {1} etc.
Marc Gravell
+1  A: 

Wat are the contents of the 'template' variable ?

Difficult to say what 's wrong with your code, but presumably, the template variable does not contain a string which as a place-holder. (Like "this is some string {0}").

I think that you should make use of the tools your IDE provides: debug the code, use watches to inspect the contents of the template variable.

Frederik Gheysels
I have posted my template.html into my original post in EDIT 1 section, any ideas what is wrong?
George2
A: 

Whats in the template file?

if there are curly brackets that are not of the format {int} or there are more than there are arguments for the format statement, it'll throw an exception.

What is the message in the exception?

It's your Css thats doing it. As somoene else mentioned you'll need to doa regex replace, or a bunch of String.Replace commands in a row mark you variables with %%VARIABLE_NAME%% and use string replacement to replace them

Omar Kooheji
I have posted my template.html into my original post in EDIT 1 section, any ideas what is wrong?
George2
Not having {0} does not cause an exception. The parameters will simply be ignored.
Joe Chung
removed that clause.
Omar Kooheji
+6  A: 

Your template contains { and } characters which need to be escaped, otherwise they confuse String.Format. Escape them using {{ and }}. Alternatively, use a different mechanism such as String.Replace.

Matt Howells
I have posted my template.html into my original post in EDIT 1 section, any ideas what is wrong?
George2
the curly braces.
Frederik Gheysels
Frederik, solution is?
George2
+5  A: 

string.Format() does not handle { and } in the format string. You need to replace { with {{ and } with }} everywhere in your template.html file. Except for the single place where you use the {0} placeholder.

Not very elegant.

Instead, consider using a template engine. See http://csharp-source.net/open-source/template-engines for some suggestions.

The next-best solution is to use regexes (with MatchEvaluator) or string.Replace(), as suggested by other answers.

Edit:

Here's an example using the StringTemplate template engine:

StringTemplate htmlpage = new StringTemplate(File.ReadAllText("template.html"));
htmlpage.SetAttribute("content", "video.wmv");
Console.WriteLine(htmlpage.ToString());

Change a single line in your template.html file:

from:

<param name="initParams" value="cc=true,markers=true,m={0}" />

to:

<param name="initParams" value="cc=true,markers=true,m=$content$" />

When the template engine encounters $content$ in the template, it replaces it with the value of the 'content' attribute that you set using code.

Using StringTemplate, you can do simple looping and conditionals within your template. See the documentation.

codeape
Agreed. string.Format is a lousy template engine because of the way it handles braces ({ and }).
Joe Chung
Hi codeape, I studied template engine, but confused why and how template engine relates to my question?
George2
Hi Joe, how template engine relates to my question? I am confused, any comments?
George2
@George2: I updated my answer with a code example.
codeape