I am using VB.Net 12, so multi-line strings are not allowed as they are in C#.
I have following code in VB.Net, which I need to convert into a single AppendFormat
. This is very easy in C# since the long string can be spread over multiple lines for better readability/maintenance, but it doesn't seem possible in VB.Net without concatenating string using the &
operator; but then the purpose of using StringBuilder gets defeated.
Question
Can I convert following VB.Net to use a single AppendFormat
without using string concatenation operator &
?
'use a stringbuilder for better string performance
Dim sb As New StringBuilder()
sb.Append("<html>")
sb.Append("<head><style>body {font-size:10pt; font-family:Arial, Sans Serif;} table{margin:0; padding:0; border-collapse:collapse;} td{border:solid 1px #eee; padding:2px;}")
sb.Append(".m{color:#f00; font-weight:bold; font-size:14pt; margin-bottom:9px;} .t{width:120px; font-weight:bold; font-size:8pt;} .d{width:500px;}")
sb.Append("</style></head>")
sb.Append("<body>")
sb.AppendFormat("<div class='m'> {0} </div><table>", ex.Message.ToString())
sb.AppendFormat("<tr><td class='t'>REQUEST URL</td><td class='d'> {0} </td></tr>", currentContext.Request.Url.OriginalString)
sb.AppendFormat("<tr><td class='t'>REQUEST PATH</td><td class='d'> {0} </td></tr>", currentContext.Request.Path)
sb.AppendFormat("<tr><td class='t'>QUERY STRING</td><td class='d'> {0} </td></tr>", currentContext.Request.QueryString.ToString())
sb.AppendFormat("<tr><td class='t'>TARGET SITE</td><td class='d'> {0} </td></tr>", ex.TargetSite.Name)
sb.AppendFormat("<tr><td class='t'>STACK TRACE</td><td class='d'> {0} </td></tr>", ex.StackTrace)
sb.AppendFormat("<tr><td class='t'>USERID</td><td class='d'> {0} </td></tr>", userId)
sb.AppendFormat("<tr><td class='t'>USER</td><td class='d'> {0} </td></tr>", userName)
sb.Append("</table>")
sb.Append("</body>")
sb.Append("</html>")
UPDATE
I got it to work using Steve's answer in which he suggested to use XML element. The only thing I needed to do was to escape curly braces by preceding each curly brace in expression with the same curly brace. The working code is as below.
Dim s As XElement = <html>
<head>
<style>
body{{font-size:10pt; font-family:Arial, Sans Serif;}}
table{{margin:0; padding:0; border-collapse:collapse;}}
td{{border:solid 1px #eee; padding:2px;}}
.m{{color:#f00; font-weight:bold; font-size:14pt; margin-bottom:9px;}}
.t{{width:120px; font-weight:bold; font-size:8pt;}}
.d{{width:500px;}}
</style>
</head>
<body>
<div class='m'>{0}</div>
<table>
<tr><td class='t'>REQUEST URL</td><td class='d'>{1}</td></tr>
<tr><td class='t'>REQUEST PATH</td><td class='d'>{2}</td></tr>"
<tr><td class='t'>QUERY STRING</td><td class='d'>{3}</td></tr>"
<tr><td class='t'>TARGET SITE</td><td class='d'>{4}</td></tr>
<tr><td class='t'>STACK TRACE</td><td class='d'>{5}</td></tr>
<tr><td class='t'>USERID</td><td class='d'>{6}</td></tr>
<tr><td class='t'>USER</td><td class='d'>{7}</td></tr>
</table>
</body>
</html>
email.Body = sb.AppendFormat(s.ToString(), ex.Message.ToString(), _
currentContext.Request.Url.OriginalString, _
currentContext.Request.Path, _
currentContext.Request.QueryString.ToString(), _
ex.TargetSite.Name, ex.StackTrace, userId, userName).ToString()
Performance Update
I tried all 3 approaches discussed here to find which one is best performing in my scenario. So, I ran my ASP.Net scenario with each of these approaches (only one was implemented for each test)
What I found using ticks elapsed of Stopwatch object for each run are as below. I ran my ASP.Net scenario 4 times for each approach. And it seems that the third approach of StringBuilder is the fastest.
I would think XElement provides better readability when someone is reading/maintaining your code, but the XElement approaches fail to beat StringBuilder in performance.
Here your code with XML Literals. I have tried to use directly a string but for some reason the result gets truncated and some part of the original text are missing. However using an XElement it works correctly
Dim s As XElement =
<html>
<head>
<style>
body {font-size:10pt; font-family:Arial, Sans Serif;}
table {margin:0; padding:0; border-collapse:collapse;}
td{border:solid 1px #eee; padding:2px;}
.m{color:#f00; font-weight:bold; font-size:14pt; margin-bottom:9px;}
.t{width:120px; font-weight:bold; font-size:8pt;}
.d{width:500px;}
</style>
</head>
<body>
<div class='m'><%= ex.Message %></div>
<table>
<tr>
<td class='t'>REQUEST URL</td>
<td class='d'><%= currentContext.Request.Url.OriginalString %></td>
</tr>
<tr>
<td class='t'>REQUEST PATH</td>
<td class='d'><%= currentContext.Request.Path %></td>
</tr>
<tr>
<td class='t'>QUERY STRING</td>
<td class='d'><%= currentContext.Request.QueryString.ToString() %></td>
</tr>
<tr>
<td class='t'>TARGET SITE</td>
<td class='d'><%= ex.TargetSite.Name %></td>
</tr>
<tr>
<td class='t'>STACK TRACE</td>
<td class='d'><%= ex.StackTrace %></td>
</tr>
<tr>
<td class='t'>USERID</td>
<td class='d'><%= userId %></td>
</tr>
<tr>
<td class='t'>USER</td>
<td class='d'><%= userName %></td>
</tr>
</table>
</body>
</html>
We can use a double curly braces around the braces in the style block and then use string.Format to replace the parameters. (Partial block taken from the code above)
....
body {{font-size:10pt; font-family:Arial, Sans Serif;}}
....
At this point we could use the String.Format to resolve in the code behind the formatting for the whole text
Dim text = String.Format(s.ToString(), ex.Message, .........)