Bill Boga and I have been working on a small MVC 6 application called Releases. Releases is an application that retrieves release notes from developer specified GitHub repositories. It's simple but powerful in communicating the evolution of our applications to users. It also allows us to develop using the latest and greatest Microsoft has to offer.
On GitHub, Markdown is king. Everything on the site is written using this simple syntax, and we wanted to continue that in our project. We wanted to retrieve the markdown of a release via GitHub's APIs and process it out to the page.
We started by wanting to write our own markdown
TagHelper but found Dave Paquette had already written one. Soon after using it, we ran into a show-stopping bug. First, look at the result from the GitHub API, and then take a look at the two following screenshots. Note the newline characters.
### Features\r\n\r\n* API namespace cleanup for tag helpers ([#578](https://github.com/aspnet/Razor/issues/578))\r\n* Refactor WriteAttribute API surface. ([#177](https://github.com/aspnet/Razor/issues/177))\r\n\r\n### Bugs Fixed\r\n\r\n* Multiple TagHelpers targeting same element cannot effectively communicate to children. ([#571](https://github.com/aspnet/Razor/issues/571))\r\n* Compilation error within tag attribute shows generated code instead of markup ([#569](https://github.com/aspnet/Razor/issues/569))\r\n* Specifying `RestrictChildren` and empty `HtmlTargetElement` results in an error ([#562](https://github.com/aspnet/Razor/issues/562))\r\n* `TreeStructureChanged` marked as `true` when whitespace is added to a page with `TagHelper`s ([#553](https://github.com/aspnet/Razor/issues/553))\r\n* Expose `FilePath` on `MappingLocation` to let Razor editor know mapping origination. ([#552](https://github.com/aspnet/Razor/issues/552))\r\n\r\n
See the difference? They look nothing alike! What's happening?
After some sleuthing, I came to this discussion on the ASP.NET/Razor repository.
The decision was made to HtmlEncode all content inside of a
TagHelper. When the content from GitHub is encoded, we lose all newline data, breaking the intention of the author. Prematurely encoding makes
TagHelper's unusable for any input coming from a user that may ultimately go through a
Be careful when using
TagHelpers if you intend to output user entered content. The user input will be mutated via HTML Encoding. Encoding will keep the application safe, but may also cause unexpected results as seen above. Bill and I decided to go back to the tried and true HTML extension method.
<!-- before (bugged) -->
<!-- after (fixed) -->
It was a rollercoaster of emotions; that ended with disappointment.
TagHelper's may look like a delicious syntactic cake, but in our case, it is something we couldn't consume.
Update : Workaround
After talking to Damien Edwards on Twitter there is a workaround, but it smells. You can wrap the content of the
TagHelper with an
HtmlString, which bypasses HTML encoding.