Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get-VstsTfsClientCredentials -OMDirectory $dir needs binding redirect for NewtonsoftJson on VS2019 #580

Closed
jessehouwing opened this issue Oct 23, 2019 · 4 comments · Fixed by #594
Assignees
Labels

Comments

@jessehouwing
Copy link
Contributor

jessehouwing commented Oct 23, 2019

Environment

azure-pipelines-task-lib version: 0.11 PowerShell

Issue Description

When calling get-vststfsclientcredentials on a VS2019 hosted agent, it fails to load with a newtonsoft.json binding issue.
It looks like other functions were patched with a assembly resolver. But this function fails.

It works when pointing to a VS2015OM or a VS2017 OM. It fails when pointing to a VS2019OM.

Expected behaviour

credentials are returned.

Actual behaviour

##[debug]Get-VstsTfsClientCredentials : Exception calling ".ctor" with "1" argument(s): "Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified."
##[debug]At D:\a\_tasks\tf-vc-add_2ef90ef1-5298-4f6a-8b99-12933fed4de4\2.0.7\ps_modules\VstsTfvcShared\VstsTfvcShared.psm1:114 char:29
##[debug]+ ... edentials = Get-VstsTfsClientCredentials -OMDirectory $(Find-VisualSt ...
##[debug]+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
##[debug]    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
##[debug]    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-VstsTfsClientCredentials
##[debug] 
##[debug]Script stack trace:
##[debug]at Get-TfsClientCredentials, D:\a\_tasks\tf-vc-add_2ef90ef1-5298-4f6a-8b99-12933fed4de4\2.0.7\ps_modules\VstsTaskSdk\ServerOMFunctions.ps1: line 152
##[debug]at Get-TfsTeamProjectCollection, D:\a\_tasks\tf-vc-add_2ef90ef1-5298-4f6a-8b99-12933fed4de4\2.0.7\ps_modules\VstsTfvcShared\VstsTfvcShared.psm1: line 114
##[debug]at Get-SourceProvider, D:\a\_tasks\tf-vc-add_2ef90ef1-5298-4f6a-8b99-12933fed4de4\2.0.7\ps_modules\VstsTfvcShared\VstsTfvcShared.psm1: line 137
##[debug]at <ScriptBlock>, D:\a\_tasks\tf-vc-add_2ef90ef1-5298-4f6a-8b99-12933fed4de4\2.0.7\TfvcAdd.v3.ps1: line 37
##[debug]at <ScriptBlock>, <No file>: line 1
##[debug]at <ScriptBlock>, <No file>: line 22
##[debug]at <ScriptBlock>, <No file>: line 18
##[debug]at <ScriptBlock>, <No file>: line 1
##[debug]Exception:
##[debug]Microsoft.PowerShell.Commands.WriteErrorException: Exception calling ".ctor" with "1" argument(s): "Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified."
##[error]Exception calling ".ctor" with "1" argument(s): "Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified."
##[debug]Processed: ##vso[task.logissue type=error]Exception calling ".ctor" with "1" argument(s): "Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified."
##[debug]Processed: ##vso[task.complete result=Failed]
@jessehouwing
Copy link
Contributor Author

Updating the function with the same assembly resolver fixes the issue.

This problem may need a more global fix?

function Get-TfsClientCredentials {
    [CmdletBinding()]
    param([string]$OMDirectory)

    Trace-EnteringInvocation -InvocationInfo $MyInvocation
    $originalErrorActionPreference = $ErrorActionPreference
    try {
        $ErrorActionPreference = 'Stop'

        # Get the endpoint.
        $endpoint = Get-Endpoint -Name SystemVssConnection -Require

++++++++++++++

        # Test if the Newtonsoft.Json DLL exists in the OM directory.
        $newtonsoftDll = [System.IO.Path]::Combine($OMDirectory, "Newtonsoft.Json.dll")
        Write-Verbose "Testing file path: '$newtonsoftDll'"
        if (!(Test-Path -LiteralPath $newtonsoftDll -PathType Leaf)) {
            Write-Verbose 'Not found. Rethrowing exception.'
            throw
        }

        # Add a binding redirect and try again. Parts of the Dev15 preview SDK have a
        # dependency on the 6.0.0.0 Newtonsoft.Json DLL, while other parts reference
        # the 8.0.0.0 Newtonsoft.Json DLL.
        Write-Verbose "Adding assembly resolver."
        $onAssemblyResolve = [System.ResolveEventHandler] {
            param($sender, $e)

            if ($e.Name -like 'Newtonsoft.Json, *') {
                Write-Verbose "Resolving '$($e.Name)' to '$newtonsoftDll'."

                return [System.Reflection.Assembly]::LoadFrom($newtonsoftDll)
            }

            return $null
        }
        [System.AppDomain]::CurrentDomain.add_AssemblyResolve($onAssemblyResolve)

++++++++++++++

        # Validate the type can be found.
        $null = Get-OMType -TypeName 'Microsoft.TeamFoundation.Client.TfsClientCredentials' -OMKind 'ExtendedClient' -OMDirectory $OMDirectory -Require

        # Construct the credentials.
        $credentials = New-Object Microsoft.TeamFoundation.Client.TfsClientCredentials($false) # Do not use default credentials.
        $credentials.AllowInteractive = $false
        $credentials.Federated = New-Object Microsoft.TeamFoundation.Client.OAuthTokenCredential([string]$endpoint.auth.parameters.AccessToken)
        return $credentials
    } catch {
        $ErrorActionPreference = $originalErrorActionPreference
        Write-Error $_
    } finally {
        Trace-LeavingInvocation -InvocationInfo $MyInvocation
    }
}

@jessehouwing
Copy link
Contributor Author

Not a question. A bug!

@damccorm
Copy link

@jessehouwing sorry for the slow response here! Any chance you want to add a PR (with the changes you mentioned above) - I think it makes sense.

This problem may need a more global fix?

Any thoughts on what that might be? I'm open to it, but also pretty comfortable just getting this instance of the problem fixed, I haven't seen any other issues

@jessehouwing
Copy link
Contributor Author

The more global fix could be to put this code into a central function, the Client OM resolve code seems to live in multiple places at the moment. I'm personally fine with this solution but future issues in this bit of code may again go unnoticed in the other places or vice versa.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants