Use Case
Sometimes we need to allow non-technical users the ability to edit portions of a web page rendered with the ASP.Net MVC Razor view engine in a production environment with editors other than Visual Studio. To facilitate the use of plain text editors outside of Visual Studio, we prefer to provide text files with a .html file extension, rather than .cshtml files for these scenarios.
We also needed to be able work with these plain text files in Visual Studio, as well as outside of Visual Studio, without disabling Visual Studio’s default setting to save files as UTF-8 with the with the Byte Order Mark (BOM), or having to re-open files saved by Visual Studio in other editors to re-encode those files without the BOM.
Problem
By default, Visual Studio encodes text files as UTF-8, with the BOM. When injecting plain text files into Razor Views with HTML.RenderPartial() method, a common go-to class to use for returning the file content from the Controller Actions is the FileContentResult class. However, the use of the FileContentResult class in conjunction with Html.RenderPartial() method will result in the characters “” appearing in the rendered output when the text files have been encoded with the BOM. These three characters appear because they are the 3 BOM byte values, which are streamed to the browsers and interpreted as ASCII.
Solution
There are many solutions, most of which involve ensuring that the BOM is never persisted to the plain text files, or searching the first three bytes of the text file for the BOM. However, we had a requirement to allow correct rendering of plain text files encoded with or without the BOM and were looking for a quicker solution that worked for both.
The solution we identified was to leverage the File.ReadAllText method with an encoding of UTF8 in combination with the ContentResult class:
[ChildActionOnly]
public ActionResult GetIndexStaticHtml()
{
var strFileData =
File.ReadAllText(Server.MapPath
("~/Views/WC/_IndexStaticContent.html"),
Encoding.UTF8);
return Content(strFileData);
}
While I didn’t dig into the guts of exactly why this works, I suspect that the Encoding.UTF8 property returns a default UTF8Encoding instance, without the optional encoderShouldEmitUTF8Identifier argument. File.ReadAllText method “attempts” identify the encoding of the text file, and re-encode with the passed in Encoder, which in this case is the default, which is configured by default to not include the BOM.
I also caution that the above solution may not work for the variety of possible combinations of UTF8 encoding forms which may be embedded by different text editors. For our use case, the above solution was a simple quick fix without the need to enumerate through the bytes of the file to search for specific bytes and encoding forms.