diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000000..0905e52204a
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,6 @@
+# https://docs.docker.com/engine/reference/builder/#dockerignore-file
+# Exclude files not relevant to the build
+# This helps to avoid unnecessarily sending large or sensitive files and directories to Docker daemon
+
+# Ignore everything and use Docker volumes
+*
diff --git a/.gitignore b/.gitignore
index a79f8547f45..e7acbd3536e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ syntax: glob
# Tool Runtime Dir
/[Tt]ools/
.dotnet/
+.dotnet-linux/
# User-specific files
*.suo
@@ -14,6 +15,7 @@ syntax: glob
# Build results
artifacts/
+artifacts-linux/
.idea/
[Dd]ebug/
[Dd]ebugPublic/
@@ -279,4 +281,4 @@ config.ps1
# Debug files
*.etl
-*.dmp
\ No newline at end of file
+*.dmp
diff --git a/Docker/Client/Linux.dockerfile b/Docker/Client/Linux.dockerfile
new file mode 100644
index 00000000000..f120ee49e97
--- /dev/null
+++ b/Docker/Client/Linux.dockerfile
@@ -0,0 +1,9 @@
+# Linux Docker image - Host WCF Client
+FROM mcr.microsoft.com/dotnet/sdk:6.0.300-focal-amd64
+
+# Run commands:
+# Setup environment variables
+# Install Root certificate
+# Run WCF Tests
+CMD /wcf/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh && /wcf/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh --cert-file /tmp/wcfrootca.crt && /wcf/eng/common/cibuild.sh -configuration Release --prepareMachine --ci --test --integrationTest
+
diff --git a/Docker/Client/Windows.dockerfile b/Docker/Client/Windows.dockerfile
new file mode 100644
index 00000000000..809c7bc0815
--- /dev/null
+++ b/Docker/Client/Windows.dockerfile
@@ -0,0 +1,12 @@
+# Windows Docker image - Host WCF Client
+FROM mcr.microsoft.com/dotnet/framework/sdk:4.8
+
+# Set Powershell as default Container shell
+SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';"]
+
+# Run commands:
+# Setup environment variables
+# Run WCF Tests
+CMD C:\wcf\src\System.Private.ServiceModel\tools\scripts\SetClientEnv-Windows.cmd; C:\wcf\eng\common\cibuild.cmd -configuration Release -prepareMachine /p:Restore=true /p:Sign=false /p:Test=true /p:IntegrationTest=true /p:Pack=false /p:Publish=false;
+
+
diff --git a/Docker/Service/Dockerfile b/Docker/Service/Dockerfile
new file mode 100644
index 00000000000..1549a87b88b
--- /dev/null
+++ b/Docker/Service/Dockerfile
@@ -0,0 +1,19 @@
+# Windows Docker image - Host WCF Service
+FROM mcr.microsoft.com/dotnet/framework/wcf
+
+# Open IIS Hosted ports
+EXPOSE 80 808 443 44345
+
+# Open Self Hosted ports
+EXPOSE 8081 8083 8084 44285 809
+
+# Set Powershell as default Container shell
+SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';"]
+
+# Set ENTRYPOINT to Powershell
+# Keeps the Service Container always running
+ENTRYPOINT ["powershell"]
+
+# Container Startup command:
+# Setup WCF IIS Hosted and Self Hosted Services, using Docker Volume at C:\wcf
+CMD ./wcf/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd 38 /p:"c:\wcf"; ./wcf/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvc.cmd; powershell
diff --git a/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config b/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config
index 970aad0e744..02dcadb10ac 100644
--- a/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config
+++ b/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config
@@ -6,6 +6,6 @@
-
+
diff --git a/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj b/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj
index 8f7a07e652f..c0731816319 100644
--- a/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj
+++ b/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj
@@ -4,14 +4,14 @@
Exe
CertificateGenerator
CertificateGenerator
- v4.5
+ v4.8
-
+
-
+
diff --git a/src/System.Private.ServiceModel/tools/scripts/BuildSource.cmd b/src/System.Private.ServiceModel/tools/scripts/BuildSource.cmd
new file mode 100644
index 00000000000..38247e6e38f
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/BuildSource.cmd
@@ -0,0 +1,7 @@
+:: Build tools on Docker host machine.
+:: This saves time during container startup and running tests (simply mount a volume for the build artifacts)
+
+:: Build certifcate generator tool
+call BuildCertUtil.cmd
+:: Build Self Hosted service
+call BuildWCFSelfHostedService.cmd
diff --git a/src/System.Private.ServiceModel/tools/scripts/BuildTest.cmd b/src/System.Private.ServiceModel/tools/scripts/BuildTest.cmd
new file mode 100644
index 00000000000..c66f8a028b8
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/BuildTest.cmd
@@ -0,0 +1,8 @@
+:: Build tests on Docker host machine.
+
+:: Windows Release Build
+call ..\..\..\..\eng\common\cibuild.cmd -configuration Release -prepareMachine /p:Root_Certificate_Installed=true /p:Client_Certificate_Installed=true /p:SSL_Available=true /p:Test=false
+
+
+
+
diff --git a/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFService.cmd b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFService.cmd
new file mode 100644
index 00000000000..471072b29cf
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFService.cmd
@@ -0,0 +1,68 @@
+echo off
+setlocal
+echo **********************************
+echo Starting WCF Service on Docker
+echo **********************************
+
+:: Use this script to start docker container for WCF Services - IIS Hosted and Self Hosted
+
+:: Variables
+set _exitCode=0
+set "ServiceImageTag=wcf:service"
+set "ServiceContainerName=WCFServiceContainer"
+set "ServiceHostName=wcfservicehost"
+
+:: Check if docker is running
+docker ps>nul 2>&1
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Please make sure docker is running.
+ goto :Failure
+)
+
+:: Check if docker is using Windows Containers
+CALL "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine
+
+:: Check if WCF service is already running
+FOR /F "tokens=* USEBACKQ" %%F IN (`docker container inspect -f '{{.State.Status}}' %ServiceContainerName%`) DO (
+if %%F == 'running' (
+ echo. & echo WCF Service container is already running.
+ goto :Done
+))
+
+:: Change directory to wcf folder
+cd ../../../..
+
+echo. & echo Building Docker image for WCF service
+
+:: Building docker image.
+docker build -f ./Docker/Service/Dockerfile -t %ServiceImageTag% .
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Building docker image failed.
+ goto :Failure
+)
+echo. & echo Building image success..
+
+:: Starting docker container from the image.
+echo. & echo Starting WCF Service Container
+:: Run docker container and mount current directory for wcf source as container volume - C:\wcf
+docker run --name %ServiceContainerName% --rm -it -d -h %ServiceHostName% -v "%cd%":"C:\wcf" %ServiceImageTag%
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Starting WCF service container failed.
+ goto :Failure
+)
+
+echo. & echo Started WCF Service Container.
+:: Print service container IP address and host name
+echo. & echo WCF Service Container IP address and Host name:
+docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" %ServiceContainerName%
+echo %ServiceHostName%
+
+exit /b
+
+:Failure
+echo. & echo Error...
+set _exitCode=1
+
+:Done
+exit /b %_exitCode%
+endlocal
diff --git a/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Linux.cmd b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Linux.cmd
new file mode 100644
index 00000000000..19200d21a99
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Linux.cmd
@@ -0,0 +1,77 @@
+echo off
+setlocal
+echo **********************************
+echo Starting WCF Client on Docker
+echo **********************************
+
+:: Use this script to start docker Linux container for WCF Client
+
+:: Variables
+set _exitCode=0
+set "TestContainerName=WCFTestContainerLinux"
+set "ServiceContainerName=WCFServiceContainer"
+set "ServiceHostName=wcfservicehost"
+
+:: Check if docker is running
+docker ps>nul 2>&1
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Please make sure docker is running.
+ goto :Failure
+)
+
+echo. & echo Checking WCF service container status and IP address.
+
+:: Switch to Windows Containers to check WCF Service status
+START /B /WAIT "" "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine
+
+:: Check if WCF service is already running
+docker container inspect -f '{{.State.Status}}' %ServiceContainerName%
+if ERRORLEVEL 1 (
+ echo. & echo Warning: WCF Service container is not running.
+ CALL DockerStartWCFService.cmd
+)
+
+:: set ServiceUri
+FOR /F "tokens=* USEBACKQ" %%F IN (`docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" %ServiceContainerName%`) DO (
+:: SET ServiceIPAddress=%%F
+SET ServiceUri=%ServiceHostName%/WcfService38
+)
+echo %ServiceUri%
+
+:: Switch to Linux Containers to run Linux tests
+START /B /WAIT "" "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchLinuxEngine
+
+:: Change directory to wcf src
+cd ../../../..
+
+echo. & echo Building Docker image for WCF client
+
+:: Building docker image.
+docker build -f ./Docker/Client/Linux.dockerfile --tag=wcf:client .
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Building docker image failed.
+ goto :Failure
+)
+echo. & echo Building image success..
+
+:: Starting docker container from the image.
+echo. & echo Starting WCF client
+:: run docker container and mount current directory for wcf source as container volume '/wcf'
+:: mount volume '.dotnet-linux' CLI cache directory inside the container as '.dotnet'
+:: mount volume 'artifacts-linux' inside the container as 'artifacts'
+:: mount volumes 'artifacts/bin' and 'artifacts/obj' inside the container, since it contains the test assemblies
+docker run --name %TestContainerName% --rm -it --memory=4g -v "%cd%":"/wcf" -v "%cd%/.dotnet-linux":"/wcf/.dotnet" -v "%cd%/artifacts-linux":"/wcf/artifacts" -v "%cd%/artifacts/bin":"/wcf/artifacts/bin" -v "%cd%/artifacts/obj":"/wcf/artifacts/obj" -e ServiceUri=%ServiceUri% wcf:client
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Starting WCF client container failed.
+ goto :Failure
+)
+
+exit /b
+
+:Failure
+echo. & echo Error...
+set _exitCode=1
+
+:Done
+exit /b %_exitCode%
+endlocal
diff --git a/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Windows.cmd b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Windows.cmd
new file mode 100644
index 00000000000..470301145c6
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Windows.cmd
@@ -0,0 +1,72 @@
+echo off
+setlocal
+echo **********************************
+echo Starting WCF Client on Docker
+echo **********************************
+
+:: Use this script to start docker Windows container for WCF Client
+
+:: Variables
+set _exitCode=0
+set "TestContainerName=WCFTestContainerWin"
+set "ServiceContainerName=WCFServiceContainer"
+set "ServiceHostName=wcfservicehost"
+
+:: Check if docker is running
+docker ps>nul 2>&1
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Please make sure docker is running.
+ goto :Failure
+)
+
+echo. & echo Checking WCF service container status and IP address.
+
+:: Switch to Windows Containers to check WCF Service status
+START /B /WAIT "" "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine
+
+:: Check if WCF service is already running
+docker container inspect -f '{{.State.Status}}' %ServiceContainerName%
+if ERRORLEVEL 1 (
+ echo. & echo Warning: WCF Service container is not running.
+ CALL DockerStartWCFService.cmd
+)
+
+:: set ServiceUri
+FOR /F "tokens=* USEBACKQ" %%F IN (`docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" %ServiceContainerName%`) DO (
+:: SET ServiceIPAddress=%%F
+SET ServiceUri=%ServiceHostName%/WcfService38
+)
+echo %ServiceUri%
+
+:: Change directory to wcf src
+cd ../../../..
+
+echo. & echo Building Docker image for WCF client
+
+:: Building docker image.
+docker build -f ./Docker/Client/Windows.dockerfile --tag=wcf:client .
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Building docker image failed.
+ goto :Failure
+)
+echo. & echo Building image success..
+
+:: Starting docker container from the image.
+
+echo. & echo Starting WCF client
+:: run docker container and mount current directory for wcf source as container volume C:\wcf
+docker run --name %TestContainerName% --rm -it --memory=4g -v "%cd%":"C:\wcf" -e ServiceUri=%ServiceUri% wcf:client
+if ERRORLEVEL 1 (
+ echo. & echo ERROR: Starting WCF client container failed.
+ goto :Failure
+)
+
+exit /b
+
+:Failure
+echo. & echo Error...
+set _exitCode=1
+
+:Done
+exit /b %_exitCode%
+endlocal
diff --git a/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh b/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh
index fae4b6d8ff5..b4ecaade001 100755
--- a/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh
+++ b/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh
@@ -20,10 +20,16 @@ acquire_certificate()
echo "Obtaining certificate from '$ServiceUri'"
- # Need to make a call as the original user as we need to write to the cert store for the current
- # user, not as root
- echo "Making a call to '${__service_host}/TestHost.svc/RootCert' as user '$SUDO_USER'"
- sudo -E -u $SUDO_USER $__curl_exe -o $__cafile "http://${__service_host}/TestHost.svc/RootCert?asPem=true"
+ # Need to make a call as the original user as we need to write to the cert store for the current user, not as root
+ # if $EUID = 0, user is 'root'
+ if [ "$EUID" -ne 0 ]; then
+ echo "Making a call to '${__service_host}/TestHost.svc/RootCert' as user '$SUDO_USER'"
+ sudo -E -u $SUDO_USER $__curl_exe -o $__cafile "http://${__service_host}/TestHost.svc/RootCert?asPem=true"
+ else
+ # Docker containers has no Sudo installed, by default it is running root user
+ echo "Making a call to '${ServiceUri}/TestHost.svc/RootCert' as root user"
+ $__curl_exe -o $__cafile "http://${ServiceUri}/TestHost.svc/RootCert?asPem=true"
+ fi
return $?
}
diff --git a/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh
new file mode 100644
index 00000000000..279cfaa92e0
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh
@@ -0,0 +1,15 @@
+# Setup environment variables
+export Windows_Authentication_Available=true
+export SPN_Available=true
+export Server_Domain_Joined=true
+export Ambient_Credentials_Available=true
+export Domain_Available=true
+export Explicit_Credentials_Available=true
+# Set username and password
+#export ExplicitUserName=
+#export ExplicitPassword=
+export SSL_Available=true
+export Root_Certificate_Installed=true
+export Client_Certificate_Installed=true
+export Peer_Certificate_Installed=true
+#export NegotiateTestDomain=
diff --git a/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Windows.cmd b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Windows.cmd
new file mode 100644
index 00000000000..08534527e62
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Windows.cmd
@@ -0,0 +1,15 @@
+:: Setup environment variables
+setx Windows_Authentication_Available true
+setx Digest_Authentication_Available true
+setx Ambient_Credentials_Available true
+setx SPN_Available true
+setx NTLM_Available true
+setx Server_Domain_Joined true
+:: Set username and password
+::setx ExplicitUserName
+::setx ExplicitPassword
+setx Domain_Available true
+setx UPN_Available true
+setx Root_Certificate_Installed true
+setx Client_Certificate_Installed true
+setx Peer_Certificate_Installed true
diff --git a/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd b/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd
index a677dd17217..941f5390e3a 100644
--- a/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd
+++ b/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd
@@ -55,7 +55,7 @@ goto :NextArg
:: Make sure this script is running in elevated
if EXIST %_logFile% del %_logFile% /f /q
-net session>nul 2>&1
+openfiles >nul 2>&1
if ERRORLEVEL 1 (
echo. & echo ERROR: Please run this script with elevated permission.
goto :Failure
@@ -181,13 +181,17 @@ if EXIST %_masterRepo% (
)
echo Use %_certService% for certificate service
-echo Build CertificateGenerator tool
-call :Run %_certRepo%\src\System.Private.ServiceModel\tools\scripts\BuildCertUtil.cmd
-if ERRORLEVEL 1 goto :Failure
echo Run CertificateGenerator tool. This will take a little while...
md %_wcfTestDir%
set certGen=%_certRepo%\artifacts\bin\CertificateGenerator\Release\CertificateGenerator.exe
+
+IF NOT EXIST "%certGen%" (
+ echo Build CertificateGenerator tool
+ call :Run %_certRepo%\src\System.Private.ServiceModel\tools\scripts\BuildCertUtil.cmd
+ if ERRORLEVEL 1 goto :Failure
+)
+
echo ^^^^^^^^^^^>%certGen%.config
call :Run %certGen%
if ERRORLEVEL 1 goto :Failure
diff --git a/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd b/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd
index 5bdf5aa410e..5efd40c7048 100644
--- a/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd
+++ b/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd
@@ -13,22 +13,28 @@ echo Preparing to launch the WCF self hosted service
if EXIST %_setupSemaphoreFile% del %_setupSemaphoreFile%
+set wcfSelfhosted=%~dp0..\..\..\..\artifacts\bin\SelfHostedWcfService\Release\SelfHostedWcfService.exe
REM Build tools
-echo Building the WCF Self hosted service...
-call %~dp0BuildWCFSelfHostedService.cmd >>%_setuplog%
-SET __EXITCODE=%ERRORLEVEL%
-if NOT [%__EXITCODE%]==[0] (
- echo ERROR: An error occurred while building WCF Self hosted Service. >>%_setuplog%
- goto :done
- )
-
-echo Building the certificate generator ...
-call %~dp0BuildCertUtil.cmd >>%_setuplog%
-set __EXITCODE=%ERRORLEVEL%
-if NOT [%__EXITCODE%]==[0] (
- echo ERROR: An error occurred while building the Certificate generator. >>%_setuplog%
- goto :done
- )
+IF NOT EXIST "%wcfSelfhosted%" (
+ echo Building the WCF Self hosted service...
+ call %~dp0BuildWCFSelfHostedService.cmd >>%_setuplog%
+ SET __EXITCODE=%ERRORLEVEL%
+ if NOT [%__EXITCODE%]==[0] (
+ echo ERROR: An error occurred while building WCF Self hosted Service. >>%_setuplog%
+ goto :done
+ )
+)
+
+set certGen=%~dp0..\..\..\..\artifacts\bin\CertificateGenerator\Release\CertificateGenerator.exe
+IF NOT EXIST "%certGen%" (
+ echo Building the certificate generator ...
+ call %~dp0BuildCertUtil.cmd >>%_setuplog%
+ set __EXITCODE=%ERRORLEVEL%
+ if NOT [%__EXITCODE%]==[0] (
+ echo ERROR: An error occurred while building the Certificate generator. >>%_setuplog%
+ goto :done
+ )
+)
REM Config Certs
REM we need the direcotry to save the test.crl file. We are investigate a way to get rid of it