Problem creating Packages using Automation API after upgrading to version 16.1.8.4404

We have our own wrapper that we were using from the VBA to create projects and packages. After recent update to 16.1.8.4404 it stopped working.

In version 16.1.5.4270 is everything working fine.

Tested also with another tool/autmation kit STraSAK that originaly developed Mr. Mazanek without luck. https://github.com/EvzenP/STraSAK

Thank you for your help.

Description of error>

Error: Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

File name: 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at System.Span`1..ctor(T[] array)
   at SharpCompress.Writers.Zip.ZipWriter.WriteEndRecord(UInt64 size)
   at SharpCompress.Writers.Zip.ZipWriter.Dispose(Boolean isDisposing)
   at SharpCompress.Writers.AbstractWriter.Dispose()
   at Sdl.ProjectApi.Implementation.ZipCompress.ZipDirectory(String packageFilepath, String localDataFolder)
   at Sdl.ProjectApi.Implementation.PackageProjectArchiver.ZipDirectory(String packageFilepath, String localDataFolder)
   at Sdl.ProjectApi.Implementation.PackageProject.CreatePackage(String packageFilePath, Boolean saveProject)
   at Sdl.ProjectApi.Implementation.AbstractProjectPackageCreation.StartImpl()
   at Sdl.ProjectApi.Implementation.PackageOperation.Start()

  • Yes we are talking about Studio 2021. This code was running like a charm in Studo 2021 (16.1.5.4270) but after update it is NOT.

    Regarding your comment about reference to Studio5. The correct version is defined in main batch file so it is not relevant..see bellow

    Thank you.

    <# : ----------------- begin batch part -----------------
    @echo off
    
    :: get Documents folder location from registry
    for /f "tokens=2*" %%A in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v "Personal" 2^>nul') do call set "DocumentsFolder=%%B"
    :: add Modules location to PSModulePath variable
    set "PSModulePath=%DocumentsFolder%\WindowsPowerShell\Modules\;%PSModulePath%"
    
    :: PowerShell location
    set POWERSHELL=%windir%\system32\WindowsPowerShell\v1.0\powershell.exe
    :: use 32-bit version on 64-bit systems!
    if exist "%windir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" (set POWERSHELL=%windir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe)
    
    :: from http://www.dostips.com/forum/viewtopic.php?f=3&t=5526&start=15#p45502
    :: invoke embedded PowerShell code + code specified on command line
    setlocal enabledelayedexpansion
    set _args=%*
    rem this is to prevent PS errors if launched with empty command line
    if not defined _args set "_args= "
    set _args=!_args:'=''!
    set _args=!_args:"="""!
    type "%~f0" | %POWERSHELL% -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "%POWERSHELL% -NoLogo -NoProfile -ExecutionPolicy Bypass -Command ([ScriptBlock]::Create([Console]::In.ReadToEnd()+';!_args!'))"
    endlocal
    
    exit /b 0
    ----------------- end batch part ----------------- #>
    
    [cultureinfo]::DefaultThreadCurrentCulture = 'en-GB'
    
    # import SDL Powershell Toolkit modules
    $StudioVersion = "Studio16"
    $Modules = @("TMHelper","ProjectHelper","GetGuids","PackageHelper")
    ForEach ($Module in $Modules) {Import-Module -Name $Module -ArgumentList $StudioVersion}

  • Hi , ,

    Trados Studio installs version 5 of that assembly with the product.

    I'm trying to understand why it's asking for version 4.0.4.1; this is a puzzle, given the input so far.

    What I would try to understand next is where this reference is creeping in from:

    • Is this problematic only when you are executing the automation via the powershell script?
    • What is executing/calling the script?  I want to exclude that this version isn't loaded from the application context that is executing the script... TBC

    In the meantime I will run some tests on my side to determine if I can reproduce; concentrating on Package export/import automation, standalone and directly as a script from your example above.

  • Hi 

    I was successful in reproducing this issue while running the powershell script that you have made note of above. The previous version of that assembly is being resolved because of a dependency in one of the references (System.Memory).

    To fix, simply include a binding redirect in the script to ensure the correct version of that assembly is resolved in the current App Domain during execution, as follows:

    $compileServicesAssembly = [System.Reflection.Assembly]::LoadFrom("$ProgramFilesDir\SDL\SDL Trados Studio\$StudioVersion\System.Runtime.CompilerServices.Unsafe.dll")
    $onAssemblyResolveEventHandler = [System.ResolveEventHandler] {
      param($sender, $e) 
      if ($e.Name.StartsWith("System.Runtime.CompilerServices.Unsafe")) {
        return $compileServicesAssembly
      }
      foreach($assembly in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
        if ($assembly.FullName -eq $e.Name) {
          return $assembly
        }
      }
      return $null
    }
    [System.AppDomain]::CurrentDomain.add_AssemblyResolve($onAssemblyResolveEventHandler)

    Note: Add this code, before you load the modules and remember to remove the reference when exiting the PS

    Example:

    cls
    
    if ("${Env:ProgramFiles(x86)}") {
        $ProgramFilesDir = "${Env:ProgramFiles(x86)}"
    }
    else {
        $ProgramFilesDir = "${Env:ProgramFiles}"
    }
    
    $StudioVersion = "Studio16"
    
    $Modules = @("TMHelper","ProjectHelper","GetGuids","PackageHelper")
    
    
    Write-Host "Add binding redirect to 'System.Runtime.CompilerServices.Unsafe.dll'";
    
    $compileServicesAssembly = [System.Reflection.Assembly]::LoadFrom("$ProgramFilesDir\SDL\SDL Trados Studio\$StudioVersion\System.Runtime.CompilerServices.Unsafe.dll")
    $onAssemblyResolveEventHandler = [System.ResolveEventHandler] {
      param($sender, $e) 
      if ($e.Name.StartsWith("System.Runtime.CompilerServices.Unsafe")) {
        return $compileServicesAssembly
      }
      foreach($assembly in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
        if ($assembly.FullName -eq $e.Name) {
          return $assembly
        }
      }
      return $null
    }
    [System.AppDomain]::CurrentDomain.add_AssemblyResolve($onAssemblyResolveEventHandler)
    
    Write-Host "Load PowerShell Toolkit modules.";
    
    ForEach ($Module in $Modules) {Import-Module -Name $Module -ArgumentList $StudioVersion}
    
    
    Write-Host "Test: Export packages.";
    
    Export-Package -ProjectLocation "C:\MyProjects\Project 1\Project 1.sdlproj" -PackageLocation "C:\Packages"
    
    Write-Host "Completed.";
    
    Remove-Module -Name "TMHelper";
    Remove-Module -Name "ProjectHelper";
    Remove-Module -name "GetGuids";
    Remove-Module -name "PackageHelper";
    [System.AppDomain]::CurrentDomain.remove_AssemblyResolve($onAssemblyResolveEventHandler)

    Try this and let me know how it goes...

  • Dear Patrick,

    Your workaround seems to be working. We will implement this fix into the production system.

    But for any future Trados releases it would be much better when any necessary assamblies would be resolved directly in trados libraries during an API call.

    Thank you.

  • Hello 

    Glad this has worked for you and you've been able to build your solution appropriately.

    But for any future Trados releases it would be much better when any necessary assamblies would be resolved directly in trados libraries during an API call.

    We would be interested to understand why you think this would be the correct approach after what has been explained here?  The issue is related to how nugget package dependencies are resolved in the App domain that is executing your code.  So applying a binding redirect in this case should not be seen as a workaround, but a requirement in providing sufficient information from the App Domain that is executing your code to choose the correct version of the assembly when multiple versions are referenced from the libraries that are loaded.

    Trados Studio handles this problem by including binding redirects in the app.config file that is loaded when the application starts.  However, when you are running your scripts from PowerShell or the Command shell, the code is executed outside of the Trados Studio context.  The solution is however the same, so far as to provide the App Domain with the same instruction via a binding redirect, so that it can disambiguate which version to resolve.

    References:

    https://docs.microsoft.com/en-us/nuget/concepts/dependency-resolution

    Paul Filkin | RWS Group

    ________________________
    Design your own training!

    You've done the courses and still need to go a little further, or still not clear? 
    Tell us what you need in our Community Solutions Hub

  • Hello,

    I confirm the problem here. We installed today a new version of Plunet and we had this same problem by creating packages. The version of system.runtime... in Trados is a 5. version. The reference points on 4.0.4.1.

    There was similar problems with other dll recently (visio file type for example), where the dll was each time younger than the assembly reference. The problems were solved in the following CU.

    Kind regards