Keep a Changelog

Developers have used different methods to inform users of changes for some time. Some put git commits into into a text file and package it with the app. Others may forgo any formal change notification. In one case you can over inform users (git commits) and then again no change tracking is just as harmful. You want a goldilocks type solution. Keep a Changelog.

The procedure and formatting around the Keep a Changelog template make it stand out. Most developers are already familiar with Markdown. It makes documents look nice with a minimal syntax. It's ideal for a Changelog.

It's also easy to integrate a Markdown page into your application. To display a markdown as in a .dotnet core web app, I used CommonMark. With a few lines of code I added a changelog to the project.

Here is the code.

@model Namespace.ChangelogViewModel

    ViewBag.Title = "Changelog";

<div class="changelog container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
public class HomeController : BaseController {
    private readonly IMarkDownToHtmlService _markdownService;

    public HomeController(
			IMarkDownToHtmlService markdownService,
			ILogger logger)
			: base(logger) {
			_markdownService = markdownService ?? throw new ArgumentNullException(nameof(markdownService));

    public async Task<ActionResult> Changelog() {
        var vm = new ChangelogViewModel {
	Changelog = await _markdownService.ConvertMdFileToHtmlAsync(filePath: "~/").ConfigureAwait(false);
	return View(vm);
public class MarkDownToHtmlService : IMarkDownToHtmlService {

   private IFileService _fileService;

    public MarkDownToHtmlService(IFileService fileService) {
         _fileService = fileService;

    /// <summary>
    /// Converts markdown to HTML
    /// </summary>
    /// <param name="filePath">Relative Server Path</param>
    /// <returns></returns>
    public async Task<String> ConvertMdFileToHtmlAsync(string filePath) {
    var serverpath = _fileService.ServerMapPath(filePath);
    using (var reader = new System.IO.StreamReader(serverpath)) {
        var fileContents = await reader.ReadToEndAsync();
	 return CommonMark.CommonMarkConverter.Convert(fileContents);

If you haven't added a changelog to your application take a few minutes and get started. Helpful document, even for developers :)