I needed to containerize a legacy .NET 3.5 application that used Entity Framework (EF) and Integrated Windows Authentication (WinAuth) to connect to SQL Server database. Since WinAuth was used, I needed to get group Managed Service Account(gMSA). However, it often takes time to get gMSA configured by system administrators who govern Active Directory security accounts. A quick workaround was to get a backup of the database and restore it locally using direct database connection bypassing WinAuth.
The idea behind Modernizing Traditional Applications methodology is to have zero code changes and as few as possible configuration changes to your existing legacy app while moving it into a Docker container. In a nutshell it’s similar to
lift-and-shiftapproach advertized by cloud providers.
Since gMSA was not ready to be used, a backup of existing database was taken and restored into SQL Server engine running in a Docker container.
The original app connection string looked like this:
<add name="LegacyDbContext" connectionString="Data Source=sqlserver;User Id=NT\dbuser;Initial Catalog=App_Table;MultipleActiveResultSets=true;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
I had to tweak it to include database credentials and disable WinAuth. The result connection string looked like this:
<add name="LegacyDbContext" connectionString="Data Source=sqlserver;User Id=dbuser;Password=dbpassword;Initial Catalog=App_Table;MultipleActiveResultSets=true;Integrated Security=false;" providerName="System.Data.SqlClient" />
As I launched .NET app in another container, I got YSOD saying that the app couldn’t connection to the database with provide credentials. The SQL Server logs showed me the following message:
Login failed for user 'dbuser'. Reason: Password did not match that for the login provided. Error: 18456, Severity: 14, State: 8
The error message turned out to be somewhat misleading since I could connect to the database using my credentials via
I got a hint from my colleague that EF connection string requies one more parameter to allow plain text credentials to be passed:
Persist Security Info=true. Also found a good explanation of the issue in stackoverflow post.
The resulting connection string that solved the issue looked like this:
<add name="LegacyDbContext" connectionString="Data Source=sqlserver;User Id=dbuser;Password=dbpassword;Initial Catalog=App_Table;MultipleActiveResultSets=true;Integrated Security=false;Persist Security Info=true;" providerName="System.Data.SqlClient" />
Another issue I had to tackle while working on this MTA was related to building a legacy app code inside of a container leveraging Docker’s multistage build feature.
The app had a dependency on
Al.exe which is a part of NetFxTools. Typically these tools can be found at
C:\Program Files (x86)\Microsoft SDKs\Windows\ path on a machine that has Visual Studio installed or WindowsSDK tools. I tried to use microsoft/dotnet-framework:3.5-sdk and microsoft/dotnet-framework:4.7.2-sdk images to build the app but neither of them had
There are a few possible solutions to this issue:
- Add installation instruction of
- If WindowsSDK files already exist on your host, you may copy them into
buildstage and set
ToolPathenvironment variable to point to
NetFxToolslocation within WindowsSDK folder. Dockerfile example:
Build command for the Dockerfile that explicitly points to Dockerfile location and sets build context to
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin where WindowsSDK tools are:
docker build -t netfxtools:4.7.2-sdk -f C:\Users\admin\Documents\projects\netfxtools\Dockerfile 'C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin'