PowerShell中.NET类型初始化器的依赖项解析问题
PowerShell 5.1中Selenium依赖加载失败与AppDomain路径问题解决
问题重现
在Windows PowerShell 5.1中使用Selenium 4.34.0做GUI自动化时,执行以下脚本:
WorkingDir = "$env:USERPROFILE\Projects\ProjectName" Set-Location $WorkingDir Add-Type -Path .\bin\Debug\netstandard2.0\WebDriver.dll EdgeDriverService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService("$WorkingDir\bin\Debug\netstandard2.0") EdgeDriver = [OpenQA.Selenium.Edge.EdgeDriver]::new([OpenQA.Selenium.Edge.EdgeDriverService]$EdgeDriverService)
会抛出OpenQA.Selenium.Command的TypeInitializationException,内部错误提示找不到System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1程序集。同时[System.AppContext]::BaseDirectory指向PowerShell的系统目录,导致Selenium Manager也会从该路径查找文件。
核心原因
- PowerShell 5.1的AppDomain在启动时就已创建,基目录固定为
C:\WINDOWS\system32\WindowsPowerShell\v1.0\,无法直接修改。CLR默认会优先从AppDomain基目录和GAC查找程序集,而非当前工作目录。 - 仅加载
WebDriver.dll不足以触发所有依赖程序集的正确加载,类型初始化时需要的依赖可能未被CLR发现。
解决方案
1. 显式加载所有相关依赖程序集
不要只加载WebDriver.dll,遍历项目输出目录下的所有dll并尝试加载,确保所有Selenium依赖都被CLR识别:
$workingDir = "$env:USERPROFILE\Projects\ProjectName\bin\Debug\netstandard2.0" Set-Location $workingDir # 遍历并加载目录下所有dll(忽略加载失败的非必要文件) Get-ChildItem -Path $workingDir -Filter "*.dll" | ForEach-Object { try { Add-Type -Path $_.FullName -ErrorAction SilentlyContinue } catch {} } # 初始化EdgeDriver $edgeDriverService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService($workingDir) $edgeDriver = [OpenQA.Selenium.Edge.EdgeDriver]::new($edgeDriverService)
2. 注册AssemblyResolve事件强制从项目目录加载
如果显式加载仍有问题,注册AppDomain的程序集解析事件,当CLR找不到程序集时,强制从项目目录查找并加载:
$workingDir = "$env:USERPROFILE\Projects\ProjectName\bin\Debug\netstandard2.0" Set-Location $workingDir # 定义程序集解析逻辑 $resolveHandler = [System.ResolveEventHandler]{ param($sender, $e) $assemblyName = [System.Reflection.AssemblyName]::new($e.Name) $targetPath = Join-Path $workingDir "$($assemblyName.Name).dll" if (Test-Path $targetPath) { return [System.Reflection.Assembly]::LoadFrom($targetPath) } return $null } # 注册事件 [System.AppDomain]::CurrentDomain.add_AssemblyResolve($resolveHandler) # 加载WebDriver并初始化 Add-Type -Path (Join-Path $workingDir "WebDriver.dll") $edgeDriverService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService($workingDir) $edgeDriver = [OpenQA.Selenium.Edge.EdgeDriver]::new($edgeDriverService) # 执行完成后移除事件(可选) [System.AppDomain]::CurrentDomain.remove_AssemblyResolve($resolveHandler)
3. 确认依赖版本匹配
检查项目输出目录下的System.Runtime.CompilerServices.Unsafe.dll版本是否为4.0.4.1,如果版本不符,可通过dotnet CLI重新安装指定版本的包:
dotnet add package System.Runtime.CompilerServices.Unsafe --version 4.5.3
(注:4.5.3版本兼容4.0.4.1的引用请求,CLR会自动重定向)
关于AppDomain路径的说明
PowerShell 5.1的AppDomain基目录无法修改,因为它是在PowerShell进程启动时就确定的。所有程序集查找的默认逻辑都会基于这个路径,因此必须通过显式加载或AssemblyResolve事件来覆盖默认行为,引导CLR到项目目录查找依赖。
内容的提问来源于stack exchange,提问作者Eileen
相关产品推荐
相关产品推荐

