Refactoring Code: Creating A File Service To Maintain Separation Of Concerns In ASP.NET Core 2016 December 11

In my previous post I wanted to focus on just integerating CommonMark.NET in my blog. I left reading content from markdown files in the ConvertMarkdownToHtml method, where it does not really belong. I want my method to just convert markdown text to html and not worry about how to obtain the markdown text (separation of concerns).

In this post I am going to explain how I refactored the following two lines to remove this dependency:

var fileFullPath = $"{_env.ContentRootPath}/Markdown/{filename}.md";
string markdownContent = File.ReadAllText(fileFullPath, Encoding.UTF8);

Note that I am under assumption that I always use static markdown (.md) files to store any markdown content. ConvertMarkdownToHtml should probably be renamed to ConvertMarkdownFileToHtml.

Currently I am storing my markdown files in the web application local directory under "Markdown" folder. Ideally, I am planning to store my markdown files in Azure Blob Storage. To enable switching to Azure blob storage a bit easier, I created IFileService interface which has a GetFileContent method. This method will take a file path and returns the content of that file. To implement retrieving content from local directory, I created LocalFileService class to implement the IFileService:

public interface IFileService
{
    string GetFileContent(string filePath);
} 

public class LocalFileService : IFileService
{
    private readonly IHostingEnvironment _env;

    public LocalFileService(IHostingEnvironment env)
    {
        _env = env;
    }

    public string GetFileContent(string filePath)
    {
        filePath = filePath.TrimStart('/');

        var fileFullPath = $"{_env.ContentRootPath}/{filePath}";
        string fileContent = File.ReadAllText(fileFullPath, Encoding.UTF8);

        return fileContent;
    }
}

With this code in place, now I can change ConvertMarkdownToHtml method implementation to the following:

public class CommonMarkDotNetService : IMarkdownService
{
    private readonly IFileService _fileService;

    public CommonMarkDotNetService(IFileService fileService)
    {
        _fileService = fileService;
    }
    public string ConvertMarkdownToHtml(string filePath)
    {
        string markdownContent = _fileService.GetFileContent(filePath);

        //... removed for brevity
    }
    //... removed for brevity
}

I have also cleaned up injecting IHostingEnvironment to CommonMarkDotNetService class, as it is no longer responsible for working with local files. It just does one thing: converting markdown files to Html content. Instead, I am injecting an implementation of IFileService. With that out of the way, I only need to configure my new service in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<IFileService, LocalFileService>();
    ...
}