Deploy Sitecore Connect for Content Hub in an existing PaaS environment

Version: 5.0

You can deploy Sitecore Connect for Content Hub (SCCH) in an existing Azure PaaS Environment.

To deploy in an existing PaaS environment, you must have an existing Sitecore XM or XP Azure PaaS Environment and Microsoft Web Deploy installed.

Note

If you are deploying a new Sitecore Azure PaaS environment, use the instructions in Deploy Sitecore Connect for Content Hub in a new PaaS environment instead.

You can install SCCH using either dat or dacpac files, depending on which Sitecore version you use. The following table shows which Sitecore versions support which installation types methods.

Sitecore version

Dacpac

Dat

Note

10.0 or below

Yes

No

10.1

Yes

Yes

The dat file must be placed in the App_Data\items folder.

10.2

No

Yes

This walkthrough describes how to:

  1. Prepare an installation folder

  2. Prepare the script input

  3. Install and configure the connector

  4. Troubleshoot installation errors

Prepare an installation folder

To prepare an installation folder:

  1. Create a local folder in your file system, for example, C:\Temp\SCCHInstallation.

  2. Download the Sitecore Connect for Content Hub WDP Package from the Sitecore download page and store it in the local folder you created.

  3. In the local folder, create a new file and name it Deploy.ps1.

  4. Open the new file with an editor such as notepad or VS Code and paste the following script inside:

    RequestResponse
    [CmdletBinding(DefaultParameterSetName = "no-arguments")]
    param(
        [Parameter(HelpMessage = "Name of the resource group in Azure to target.")]
        [string]$ResourceGroupName,
    
        [Parameter(HelpMessage = "Name of the web app in Azure to target.")]
        [string]$WebAppName,
    
        [Parameter(HelpMessage = "Path to the WDP to deploy to the target.")]
        [string]$WdpPackagePath,
    
        [Parameter(HelpMessage = "Content Hub Client Id.")]
        [string]$CHClientId,
    
        [Parameter(HelpMessage = "Content Hub Client Secret.")]
        [string]$CHClientSecret,
    
        [Parameter(HelpMessage = "Content Hub Username.")]
        [string]$CHUserName,
    
        [Parameter(HelpMessage = "Content Hub Password.")]
        [string]$CHPassword,
    
        [Parameter(HelpMessage = "Content Hub URI.")]
        [string]$CHUri,
    
        [Parameter(HelpMessage = "Content Hub Azure Service Bus connection string path in.")]
        [string]$CHServiceBusEntityPathIn,
    
        [Parameter(HelpMessage = "Content Hub Subscription name. (must be unique per Sitecore CM deployment)")]
        [string]$CHServiceBusSubscription,
    
        [Parameter(HelpMessage = "Content Hub Azure Service Bus connection string path out.")]
        [string]$CHServiceBusEntityPathOut,
    
        [Parameter(HelpMessage = "Content Hub Search Page Uri.")]
        [string]$CHSearchPage,
    
        [Parameter(HelpMessage = "Content Hub External Redirect Key.")]
        [string]$CHExternalRedirectKey = "Sitecore",
    
        [Parameter(HelpMessage = "Path to MSDeploy.")]
        [string]$MsDeployPath = "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe",
    
        [Parameter(HelpMessage = "Skips Azure Login when True.")]
        [switch]$SkipAzureLogin = $False,
    
        [Parameter(HelpMessage = "Amount of retry attempts. 6 by default which with default retryinterval would come down to 1 minute.")]
        [int]$RetryAttempts = 6,
    
        [Parameter(HelpMessage = "Amount of time to wait between retries in milliseconds. 10000 by default which is 10 seconds which adds up to 1 minute with default retry attempts.")]
        [int]$RetryInterval = 10000
    )
    
    Add-Type -AssemblyName "System.IO.Compression.FileSystem"
    
    function PreparePath($path) {
        if(-Not (Test-Path $path)) {
            $result = New-Item -Path $path -Type Directory -Force
        } else {
            $result = Resolve-Path $path
        }
    
        return $result
    }
    
    function UnzipFolder($zipfile, $folder, $dst) {
        [IO.Compression.ZipFile]::OpenRead($zipfile).Entries | Where-Object {
            ($_.FullName -like "$folder/*") -and ($_.Length -gt 0)
        } | ForEach-Object {
            $parent = Split-Path ($_.FullName -replace $folder, '')
            $parent = PreparePath (Join-Path $dst $parent)
            $file = Join-Path $parent $_.Name
            [IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
        }
    }
    
    function DownloadWebsiteFile($filePath, $downloadFolderName) {
        $basePath = Split-Path ".\$downloadFolderName\$filePath"
        $fileName = Split-Path $filePath -Leaf
        if(-Not (Test-Path ".\$downloadFolderName\$filePath")) {
            New-Item -Path $basePath -Type Directory -Force
        }
        $outFilePath = Join-Path (Resolve-Path "$basePath") $fileName
        Invoke-WebRequest -Uri "https://$WebAppName.scm.azurewebsites.net/api/vfs/site/wwwroot/$filePath" -Headers @{"Authorization"=("Basic {0}" -f $base64AuthInfo)} -Method GET -OutFile $outFilePath
    }
    
    function UploadWebsiteFile($filePath, $uploadFilePath) {
        Invoke-WebRequest -Uri "https://$WebAppName.scm.azurewebsites.net/api/vfs/site/wwwroot/$filePath" -Headers @{"Authorization"=("Basic {0}" -f $base64AuthInfo);"If-Match"="*"} -Method PUT -InFile $uploadFilePath
    }
    
    function ApplyTransform($filePath, $xdtFilePath) {
        Write-Verbose "Applying XDT transformation '$xdtFilePath' on '$filePath'..."
    
        $target = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
        $target.PreserveWhitespace = $true
        $target.Load($filePath);
        
        $transformation = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdtFilePath);
        
        if ($transformation.Apply($target) -eq $false)
        {
            throw "XDT transformation failed."
        }
        
        $target.Save($filePath);
    }
    
    if(-Not (Test-Path $MsDeployPath)) {
        Write-Host "MS Deploy was not found at `"$MsDeployPath`"!" -ForegroundColor Red
        return
    }
    
    if(-Not $SkipAzureLogin) {
        Write-Host "Logging into Azure..." -ForegroundColor Green
        & az login
    }
    
    
    Write-Host "Fetching Publish Profile..." -ForegroundColor Green
    $publishProfile = az webapp deployment list-publishing-profiles --resource-group $ResourceGroupName --name $WebAppName --query "[?publishMethod=='MSDeploy']" | ConvertFrom-Json
    $userName = $publishProfile.userName
    $password = $publishProfile.userPWD
    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userName, $password)))
    
    
    Write-Host "Preparing configuration..." -ForegroundColor Green
    $xdtsPath = (PreparePath ".\xdts")
    UnzipFolder $WdpPackagePath "Content/Website/App_Data/Transforms/scch/xdts" $xdtsPath
    Get-ChildItem $xdtsPath -File -Include "*.xdt" -Recurse | ForEach-Object {
        $targetWebsiteFile = $_.FullName.Replace("$xdtsPath\", "").Replace("\", "/").Replace(".xdt", "")
        DownloadWebsiteFile $targetWebsiteFile "Configuration"
    }
    $configurationPath = (PreparePath ".\Configuration")
    $currentDateTime = (Get-Date).ToString("dd-MM-yyyy-hh-mm-ss")
    $backupPath = (PreparePath ".\Backup-$currentDateTime")
    robocopy $configurationPath $backupPath /s
    
    
    Write-Host "Preparing transformations..." -ForegroundColor Green
    $nupkgPath = Join-Path (Resolve-Path ".") "microsoft.web.xdt.3.1.0.nupkg"
    $xdtDllBinPath = PreparePath ".\bin"
    Invoke-WebRequest -Uri "https://www.nuget.org/api/v2/package/Microsoft.Web.Xdt/3.1.0" -OutFile $nupkgPath
    UnzipFolder $nupkgPath "lib/netstandard2.0" $xdtDllBinPath
    Add-Type -Path (Resolve-Path ".\bin\Microsoft.Web.XmlTransform.dll")
    
    
    Write-Host "Fill ConnectionStrings..." -ForegroundColor Green
    $connectionStringsXdtPath = Join-Path $xdtsPath "App_Config\ConnectionStrings.config.xdt"
    ((Get-Content -Path $connectionStringsXdtPath -Raw).Replace("{client_id}", $CHClientId).Replace("{client_secret}", $CHClientSecret).Replace("{username}", $CHUserName).Replace("{password}", $CHPassword).Replace("{uri}", $CHUri).Replace("{Azure Service Bus connection string with incoming topic}", $CHServiceBusEntityPathIn).Replace("{Subscription name}", $CHServiceBusSubscription).Replace("{Azure Service Bus connection string with outcoming topic}", $CHServiceBusEntityPathOut).Replace("{Content Hub search page URI}", $CHSearchPage).Replace("{External redirect key}", $CHExternalRedirectKey)) | Set-Content -Path $connectionStringsXdtPath
    
    
    Write-Host "Running transformations..." -ForegroundColor Green
    Get-ChildItem $xdtsPath -File -Include "*.xdt" -Recurse | ForEach-Object {
        $targetFilePath = $_.FullName.Replace($xdtsPath, $configurationPath).Replace(".xdt", "")
        if (-not(Test-Path $targetFilePath -PathType Leaf)) {
            Write-Verbose "No matching file '$targetFilePath' for transformation '$($_.FullName)'. Skipping..."
        } else {
            ApplyTransform $targetFilePath $_.FullName
        }
    }
    
    
    Write-Host "Starting MSDeploy..." -ForegroundColor Green
    $verb = "-verb:sync"
    $source = "-source:package=`"$WdpPackagePath`""
    $dest = "-dest:auto,ComputerName=`"https://$WebAppName.scm.azurewebsites.net/msdeploy.axd?site=$WebAppName`",UserName=`"$userName`",Password=`"$password`",AuthType=`"Basic`""
    $iisWebAppParam = "-setParam:name=`"IIS Web Application Name`",value=`"$WebAppName`""
    $coreParam = "-setParam:name=`"Core Admin Connection String`",value=`"notUsed`""
    $masterParam = "-setParam:name=`"Master Admin Connection String`",value=`"notUsed`""
    $skipDbFullSql = "-skip:objectName=dbFullSql"
    $skipDbDacFx = "-skip:objectName=dbDacFx"
    $doNotDeleteRule = "-enableRule:DoNotDeleteRule"
    $appOfflineRule = "-enableRule:AppOffline"
    $retryAttemptsParam = "-retryAttempts:$RetryAttempts"
    $retryIntervalParam = "-retryInterval:$RetryInterval"
    $verboseParam = "-verbose"
    Invoke-Expression "& '$MsDeployPath' --% $verb $source $dest $iisWebAppParam $coreParam $masterParam $skipDbFullSql $skipDbDacFx $doNotDeleteRule $appOfflineRule $retryAttemptsParam $retryIntervalParam $verboseParam"
    
    
    Write-Host "Uploading configuration..." -ForegroundColor Green
    Get-ChildItem $configurationPath -File -Recurse | ForEach-Object {
        $targetWebsiteFile = $_.FullName.Replace("$configurationPath\", "").Replace("\", "/")
        UploadWebsiteFile $targetWebsiteFile $_.FullName
    }
    
  5. If you are installing SCCH on a version earlier than Sitecore Experience Platform (SXP) 10.1, using dacpac files, remove the $skipDbFullSql and $skipDbDacFx parameters in the script. The script line will look like this:

    RequestResponse
    Invoke-Expression "& '$MsDeployPath' --% $verb $source $dest $iisWebAppParam $coreParam $masterParam $doNotDeleteRule $appOfflineRule $retryAttemptsParam $retryIntervalParam $verboseParam"

    After you remove the parameters, update the connection strings for the Core and Master admin parameters:

    RequestResponse
    $coreParam = "-setParam:name=`"Core Admin Connection String`",value=`"<core connection string>`""
    $masterParam = "-setParam:name=`"Master Admin Connection String`",value=`"<master connection string>`"
    Note

    You can find the connection strings in Azure Portal by connecting to your Azure SQL database.

  6. Save and close the file.

Prepare the script input

To successfully run the script and install and configure the connector, you must prepare the following parameters:

  • ResourceGroupName - the resource group name in Azure you want to install to.

  • WebAppName - the name of the Web App in Azure you want to install to.

  • CHClientId and CHClientSecret - a Content Hub OAuth Client ID and Client Secret. (See Authentication for how to create these).

  • CHUserName and CHPassword - a Content Hub username and password that is used as the identification of Sitecore to access Content Hub.

  • CHUri - the URI to your Content Hub instance, for example, https://mysandbox.stylelabs.io/.

  • CHServiceBusEntityPathIn and CHServiceBusEntityPathOut - to find these connection strings, in Content Hub, create a new action of the type M Azure Service Bus. Make a note of the connection strings in Hub out for CHServiceBusEntityPathIn and Hub in for CHServiceBusEntityPathOut. For example:

    The Edit action dialog box showing the Hub in and Hub out connection strings
  • CHServiceBusSubscription - the name of your Sitecore subscription.

  • CHSearchPage - the URI to the Search Page you want to use to select DAM Assets, for example, https://mysandbox.stylelabs.io/en-us/sitecore-dam-connect/approved-assets.

Install and configure the connector

To run the installation of the connector and apply the configuration:

  1. Open a PowerShell window with administrator access.

  2. Navigate to your local folder. For example:

    RequestResponse
    cd "C:\Temp\SCCHInstallation"
  3. Run the following command:

    RequestResponse
    az account set –subscription <subscription name or id>
  4. Run the following command with the parameters you have prepared:

    RequestResponse
    .\Deploy.ps1 -ResourceGroupName "<MyResourceGroup>" -WebAppName "<MyWebApp>" -WdpPackagePath "C:\Temp\SCCHInstallation\Sitecore.Connector.ContentHub.WDP.5.0.0-r00328.4145.scwdp.zip" -CHClientId "<ClientId>" -CHClientSecret "<ClientSecret>" -CHUserName "<UserName>" -CHPassword "<Password>" -CHUri "https://mysandbox.stylelabs.io/" -CHServiceBusEntityPathIn "<Hub out connectionstring>" -CHServiceBusSubscription "<MySitecoreSubscription>" -CHServiceBusEntityPathOut "<Hub in connectionstring>" -CHSearchPage "https://mysandbox.stylelabs.io/en-us/sitecore-dam-connect/approved-assets"
    Note

    You must run this command against both your CM and your CD Azure PaaS Web Applications.

  5. If you use the DAM functionality in SCCH, to allow the connector to select assets from Content Hub, add all hostnames to the Content-Security-Policy tag.

    Note

    Ensure you have enabled CMP or DAM.

Troubleshoot installation errors

You might encounter the following error(s) when installing SCCH in an existing Azure PaaS environment.

Error: Could not load file or assembly ‘System.Runtime.CompilerService.Unsafe’

This error can occur when you have configured an Azure redis cache. If you get a version conflict error for System.Runtime.CompilerService.Unsafe version 4.0.4.1, add the following node to your webconfig file:

RequestResponse
<dependentAssembly>
    <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral"/>
    <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.0"/>
</dependentAssembly>

Do you have some feedback for us?

If you have suggestions for improving this article,