Repository navigation
@Raw
Alexander Selishchev edited this page Oct 22, 2026
·
13 revisions
By default, RazorEngine does not encode values to be HTML safe, and there are reasons for that. This means:
- you need to escape values yourself
- you need to implement the
@Rawhelper yourself
But don't worry, this page is here to help.
IRazorEngine razorEngine = new RazorEngine();
IRazorEngineCompiledTemplate template = razorEngine.Compile("Hello @Model.Name");
string result = template.Run(new
{
Name = "<b>Test</b>"
});
Console.WriteLine(result);will output
Hello <b>Test</b>
RazorEngine razorEngine = new RazorEngine();
var razorEngineCompiledTemplate = razorEngine.Compile<HtmlSafeTemplate>(
"<div title=\"@Model.FirstName\">This is now safe: @Model.FirstName</div>\n" +
"<div>but not this: @Raw(Model.FirstName)</div>");
string result = razorEngineCompiledTemplate.Run(instance =>
{
instance.Model = new AnonymousTypeWrapper(new
{
FirstName = "<script>alert(\"1\");</script>",
LastName = "123"
});
});
Console.WriteLine(result);Output:
<div title="<script>alert("1");</script>">This is now safe: <script>alert("1");</script></div>
<div>but not this: <script>alert("1");</script></div>
using System.Text.Encodings.Web;
using System.Text.Unicode;
public class HtmlSafeTemplate : RazorEngineTemplateBase
{
// HtmlEncoder.Default escapes everything outside Basic Latin (Cyrillic, CJK etc.) as &#x...;
private static readonly HtmlEncoder Encoder = HtmlEncoder.Create(UnicodeRanges.All);
class RawContent
{
public object Value { get; set; }
public RawContent(object value)
{
Value = value;
}
}
public object Raw(object value)
{
return new RawContent(value);
}
public override void Write(object obj = null)
{
object value = obj is RawContent rawContent
? rawContent.Value
: Encoder.Encode(obj?.ToString() ?? string.Empty);
base.Write(value);
}
public override void WriteAttributeValue(string prefix, int prefixOffset, object value, int valueOffset, int valueLength, bool isLiteral)
{
// literal parts of attribute come from the template as is and may already contain entities like &
if (!isLiteral)
{
value = value is RawContent rawContent
? rawContent.Value
: Encoder.Encode(value?.ToString() ?? string.Empty);
}
base.WriteAttributeValue(prefix, prefixOffset, value, valueOffset, valueLength, isLiteral);
}
}public class HtmlSafeTemplate : RazorEngineTemplateBase
{
class RawContent
{
public object Value { get; set; }
public RawContent(object value)
{
Value = value;
}
}
public object Raw(object value)
{
return new RawContent(value);
}
public override void Write(object obj = null)
{
object value = obj is RawContent rawContent
? rawContent.Value
: System.Web.HttpUtility.HtmlEncode(obj);
base.Write(value);
}
public override void WriteAttributeValue(string prefix, int prefixOffset, object value, int valueOffset, int valueLength, bool isLiteral)
{
// literal parts of attribute come from the template as is and may already contain entities like &
if (!isLiteral)
{
value = value is RawContent rawContent
? rawContent.Value
: System.Web.HttpUtility.HtmlAttributeEncode(value?.ToString());
}
base.WriteAttributeValue(prefix, prefixOffset, value, valueOffset, valueLength, isLiteral);
}
}- Only values written with
@are encoded. Literal text of the template, including literal parts of attributes likehref="/search?a=1&q=@Model.Q", is written as is. - HTML encoding is not suitable for JavaScript: in
onclick="go('@Model.Q')"the browser decodes'back to'before running the script (so the value can break out of the string), and inside<script>entities are not decoded at all. UseJavaScriptEncoderor pass data viadata-*attributes for such cases. - Characters outside the Basic Multilingual Plane (emoji etc.) are always written as
😀entities, browsers render them correctly.