Skip to content

Conversation

@nmummau
Copy link
Contributor

@nmummau nmummau commented Oct 20, 2025

Proposal to resolve issue #733

This PR provides a new build target "PublishContainer" which will create a docker image that contains both your project's dacpac and sqlpackage. This image can then be run to publish your dacpac to a target database.

Demo video for the PR feature: https://youtu.be/NaCNs0OOUbM

How I've tested this

I've been building and packing the SDK with

dotnet build -c Release &&
dotnet pack MSBuild.Sdk.SqlProj.csproj -c Release

I then copy the nupkg...
C:\code\MSBuild.Sdk.SqlProj\src\MSBuild.Sdk.SqlProj\bin\Release\MSBuild.Sdk.SqlProj.3.3.0-beta.16.g87c1e17ddb.nupkg

...to a directory I use as a local NuGet feed
C:\LocalFeed

Then in the project I want to use this, for me this is c/code/wes/inventory/src

dotnet nuget locals all --clear

🧱 Then build with the PublishContainer target

dotnet build ./WES.Inventory.Database/WES.Inventory.Database.csproj \
-t:PublishContainer \
-c Release \
-v:m

Due to the name of the project I'm using this with my resulting docker image is named wes.inventory.database-publisher:release

You can look into the files within the image

MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL="*" \
docker run --rm --entrypoint sh wes.inventory.database-publisher:release \
-lc "ls -l /work"

results:

-rwxr-xr-x 1 root root  14442 Oct 19 15:31 WES.Inventory.Database.dacpac
-rwxr-xr-x 1 root root 180940 Apr 11  2025 master.dacpac

🎊 Finally you can run the image (git bash) to publish your dacpac to the target database

MSYS_NO_PATHCONV=1 \
docker run --rm wes.inventory.database-publisher:release \
-TargetServerName:host.docker.internal,14333 \
-TargetDatabaseName:WES_001_inv \
-TargetUser:sa \
-TargetPassword:YourPassword123! \
-TargetTrustServerCertificate:true \
"/p:DropObjectsNotInSource=True" "/p:BlockOnPossibleDataLoss=False"

results

...
Publishing to database 'WES_001_inv' on server 'host.docker.internal,14333'.
Initializing deployment (Start)
Initializing deployment (Complete)
Analyzing deployment plan (Start)
Analyzing deployment plan (Complete)
Updating database (Start)
Creating database WES_001_inv...
Creating Schema [wes]...
...

@ErikEJ
Copy link
Collaborator

ErikEJ commented Oct 20, 2025

@nmummau Why do we need to have the sqlpackage version involved?

Could we not just use:

dotnet tool install -g Mircosoft.Sqlpackage

@ErikEJ
Copy link
Collaborator

ErikEJ commented Oct 20, 2025

@nmummau And thanks for doing this, this is a great addition!

@ErikEJ
Copy link
Collaborator

ErikEJ commented Oct 20, 2025

@nmummau Just watched the video - a great help for me (not being a docker expert).

Some thoughts:

  • I suggest we avoid any nice to have targets/features and just implement the bare essentials this time (and await user feedback and suggestions)
  • How would we handle a publish profile (an xml file with publish parameter) in this scenario?
  • How do you add addtional publish parameters?

@nmummau
Copy link
Contributor Author

nmummau commented Oct 20, 2025

@nmummau Why do we need to have the sqlpackage version involved?

Could we not just use:

dotnet tool install -g Mircosoft.Sqlpackage

Short answer: we can use the .NET global tool, but the current approach (pulling the NuGet nupkg/platform zip) is more deterministic and works on the slimmer base image without extra fuss.

dotnet tool install -g ... requires the .NET SDK as the dotnet/runtime image doesn't include the tooling needed to install global tools

Also, pinning to a SQLPACKAGE_VERSION will give us deterministic versioning. Even if we used the global tool we should probably pin the version (dotnet tool install -g Microsoft.SqlPackage --version 162.3.15). Because If you leave it floating, upgrades happen silently, which can introduce subtle failures.

If you think we should use the .NET SDK with the global tool, instead of what I have, I can give that a shot and see what I come up with. Thought?

@ErikEJ
Copy link
Collaborator

ErikEJ commented Oct 20, 2025

requires the .NET SDK as the dotnet/runtime image doesn't include the tooling needed to install global tools

@nmummau Ah, in that case, let's stick to the runtime only image!

Wonder if we could move the DacFX/Sqlpackage version to the Directory.Build.Props file, and use that both here and in the .Dacpac tool?

- paird with video demo: https://youtu.be/NaCNs0OOUbM
- new build target PublishContainer will create a docker image that can be run to publish your project's dacpac to a target database via sqlpackage
- Move hardcoded DacFx version to Sdk.props
- Reference $(DacFxVersion) in DacpacTool.csproj
- Set SqlPackageVersion from DacFxVersion in Sdk.targets
- Ensures SDK owns versioning and keeps DacFx and SqlPackage in sync
@nmummau
Copy link
Contributor Author

nmummau commented Oct 21, 2025

Wonder if we could move the DacFX/Sqlpackage version to the Directory.Build.Props file, and use that both here and in the .Dacpac tool?

@ErikEJ I experimented with a few approaches, and the commit 3ea4a94 is what I landed on.

This does essentially what you were suggesting — it centralizes the version of DacFx so that it’s also the version of SqlPackage used in the publish process.

From what I found digging through MSBuild behavior, Sdk.props is imported before the Directory.Build.props and the project .csproj file, which means this is the most reliable place to pin the version at the SDK level. That way:

  • DacFxVersion is defined once in Sdk.props
  • It’s available to both DacpacTool.csproj (via $(DacFxVersion)) and Sdk.targets (edit: 🔴 this does not work!)
  • Sdk.targets then sets SqlPackageVersion from DacFxVersion to ensure they always stay in sync

This effectively gives the SDK full ownership of the version number, without relying on the consumer to specify anything.

This means the SDK is now the only place to bump when needed. This is probably the cleanest if we want SDK maintainers to fully own the DacFx/SqlPackage version, and to keep them in sync.

The previous change attempted to use the $(DacFxVersion) property from the SDK to set the Microsoft.SqlServer.DacFx package version in DacpacTool.csproj.

This didn’t work because DacpacTool.csproj does not import the custom SDK and therefore has no knowledge of properties defined in Sdk.props.
@nmummau
Copy link
Contributor Author

nmummau commented Oct 21, 2025

@ErikEJ to my previous comment... just kidding, that won't work! ☹️ See commit 778a3c7 where I made a few tweaks.

The DaxFx version is now back directly in DacpacTool.csproj, and the SqlPackageVersion is set in Sdk.props

I'm open to ideas, but I don't see a clear path to keeping the DacpacTool.csproj directly in sync with the version that the SDK uses for SqlPackage.

@nmummau
Copy link
Contributor Author

nmummau commented Oct 21, 2025

  • How would we handle a publish profile (an xml file with publish parameter) in this scenario?
  • How do you add addtional publish parameters?

@ErikEJ This is a great callout. Give me some time to come up with a solution here.

@nmummau
Copy link
Contributor Author

nmummau commented Oct 24, 2025

@ErikEJ this is aside, but I wanted to show you a PR (with another guide video) I created for a different project where I implemented some Docker tooling for the purpose of deploying to a containerized database using a .dacpac with sqlpackage. This mechanism works, but should show off to you why it would be very nice if the SDK could provide that functionality out of the box

Eventuous/eventuous#452

@jmezach
Copy link
Member

jmezach commented Oct 28, 2025

@nmummau I really see the value of having something like this in the box. Having the ability to just publish a database project as a container that when run would deploy it to a target database can help in a lot of scenario's.

While I appreciate the effort you've put into this and I'm not entirely sure this is the right approach to implementing this feature. In its current form it seems that we're running docker on the command line. This obviously requires some form of Docker runtime to be installed on the machine. Looking at the built-in support for the .NET SDK it seems that this is not required there, see https://learn.microsoft.com/en-us/dotnet/core/containers/sdk-publish#prerequisites. I think that if it works like that this feature would be even more powerful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants