Streamline Deploying your documentation with DocFx 2, DotNet 5, and Docker

At the time of writing this DocFx is not playing well DotNet (.NET) 5 Projects. The error specifically is reading .csproj and .sln files to get the API documentation, or your 3 slash code comments. This presented me with a slight problem, and here was my solution.

I was needing to publish my documentation for a work project since we just upgraded to .NET 5. So I first was working on running Docfx with Mono inside a docker container it took me a few minutes to get that running after getting that to successful work I came across the bug between .NET 5 & Docfx, noted here: Github. So you just have to build your code, let docfx read those .dll files, then finally deploy to a web server for view.

To achieve this I built a 3 stage docker file to get the documentation built you can see an example of the Dockerfile below.

# build .dll files for docfx to inspect
FROM mcr.microsoft.com/dotnet/sdk:5.0.102-alpine3.12-amd64 AS code-env

WORKDIR /app

COPY . .

RUN dotnet publish -o ./.build src/FileShare.API

# build docs with docfx using mono
FROM mono as docs-env

RUN apt update && apt install -y unzip wget

WORKDIR /tools

RUN wget https://github.com/dotnet/docfx/releases/download/v2.56.7/docfx.zip

RUN unzip docfx.zip -d ./docfx

WORKDIR /build

COPY --from=code-env /app/.build .build

COPY . .

RUN mono /tools/docfx/docfx.exe build docfx_project/docfx.json

# deploy using nginx for static file hosting
FROM nginx:latest

WORKDIR /var/www/html

COPY --from=docs-env /build/docfx_project/_site .

WORKDIR /etc/nginx/conf.d

COPY ./docfx_project/default.conf default.conf

Why I use Docker for documentation deployment

I have used docker deploying services for some time now. I like that there is no configuring the service on a server, or a developer on another team, can pull it and run it locally, so they have access offline. It also integrates well in my build pipeline.

Windows File Shares & Dot Net Core – Part 1

A project for work required me to interact with a Windows File Share. I had other constraints as well that made this a little more difficult. I needed to be cross-platform compatible (run on both Windows and Linux) and I couldn’t use the SMB1 protocol due to security vulnerabilities. Here are my findings and a basic implementation of how I interact with Windows File Shares with Dot Net Core.

What is SMB and What is Wrong with SMB1?

SMB or Server Message Block is a protocol dating back to 1983 and created by IBM to create network file shares on DOS systems. Microsoft got involved and merged it with other products of theirs for better integration. Microsoft has continued to evolve it over the years and has a new standard that was introduced in 2006.

Recently there have been some growing concerns about security issues with the SMB protocol version 1, relating to denial of service attacks and remote code execution. This caused Microsoft to put the SMB 1 protocol on the depreciated list for Windows Server 2012, and it is disabled in Windows Server 2016 by default.

Cross-Platform and Why not mount the share on Unix Systems?

The key benefit of using Dot Net Core is that apps can run on a variety of hosts, not just Linux or Windows. This allows the user to install and run on their preferred system. In my case, we have customers that run our application on-site and we use Linux for our cloud infrastructure. You should minimize any branching based on the platform, if at all possible.

With Unix systems such as Linux, to work with Windows file shares typically you would mount them as drives and they work like a directory would. I find this method hard to work with for a few reasons. The main reason I dislike mounting shares for Linux systems is that you have to have elevated permissions to mount the drive, which may not always be possible, especially in the case of Docker containers.

The Code…

I tried a couple of different libraries and finally settled on SMBLibrary, available here https://github.com/TalAloni/SMBLibrary. This library was the only one I could find with Windows File Share Access using SMB version 2 protocol. You need to create a connection then access the file in blocks of 65536 bytes. This is a known limit of early implementations of the protocol.

The client implements Idisposable so we can use the c# using statement to set the connection and authentication up. See the example below for a sample client. While this implementation is not perfect it is the first time I have attempted to implement IDisposable.

Then we have a service that we pass a DTO into the method to retrieve a file from the share and display the contents. In the example below, we access the file in blocks and add them together, before we finally read out the byte array.

I have a full repository on GitHub implementing everything discussed in this post, available here: https://github.com/rebelweb/DotNetCoreFileShare. In part 2 we will look at writing files to the share.