You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSIS包调用WinSCP C#脚本上传SFTP报UnsafeInvokeInternal错误求助

SSIS脚本SFTP上传UnsafeInvokeInternal错误修复

问题现象

在SSIS脚本任务中使用C#调用WinSCP实现文件从SQL Server导出后上传到SFTP目录时,运行抛出System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters)错误,尝试通过gacutil注册WinSCP程序集未解决问题。

核心原因

该错误是SSIS脚本任务反射调用内部方法时捕获异常的外层包装,不是根本故障点,实际触发原因集中在以下几类:

  • GAC注册命令输入错误:执行注册时输入的程序集名为WinSCPnet.dl,缺失后缀最后一个字符,实际未完成程序集注册
  • WinSCP组件不匹配:WinSCPnet.dll .NET程序集与WinSCP.exe原生程序版本不一致,或程序位数(32/64位)与SSIS运行时位数不匹配,导致程序集加载失败
  • 路径与权限问题:配置的WinSCP.exe存储在带访问限制的共享目录,SQL Server服务/代理运行账号无该目录的执行权限、源文件读取权限或SFTP目录写入权限
  • 脚本逻辑漏洞:未区分密码认证与私钥认证场景,本地文件路径拼接未做规范化处理,路径错误导致上传失败

修复步骤

  1. 完成正确的GAC注册
    选择与项目.NET Framework版本匹配的gacutil工具(当前环境使用NETFX 4.6.1版本工具即可),执行正确的注册命令,注意核对程序集文件名完整:
    "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\gacutil.exe" /i WinSCPnet.dll
    
    注册成功后工具会返回程序集添加到全局缓存成功的提示。注意选择对应.NET Framework 4.0构建的WinSCPnet.dll版本,不要使用.NET Core/.NET Standard版本的程序集。
  2. 统一WinSCP组件版本与部署位置
    • 配套使用同版本的WinSCPnet.dll和WinSCP.exe,禁止跨版本混用
    • 根据SSIS项目的运行时位数选择对应程序:项目开启64位运行时则使用64位WinSCP.exe,开启32位兼容模式则使用32位版本
    • 将两个文件统一部署到服务器本地固定目录(如C:\Program Files\WinSCP\),不要放在带特殊权限限制的管理共享目录,给SQL Server数据库引擎服务、SQL Server代理服务的运行账号授予该目录的读取、执行权限。
  3. 修正脚本逻辑问题
    原脚本存在认证逻辑缺失、路径拼接不规范的问题,替换核心执行代码如下:
    public void Main()
    {
        String HostName = (String)Dts.Variables["User::HostName"].Value;
        int PortNumber = (int)Dts.Variables["User::PortNumber"].Value;
        String Username = (String)Dts.Variables["User::Username"].Value;
        String Password = (String)Dts.Variables["User::Password"].Value;
        String FileLocation = (String)Dts.Variables["User::FileLocation"].Value;
        String FileName = (String)Dts.Variables["User::FileName"].Value;
        String RemoteLocation = (String)Dts.Variables["User::RemoteLocation"].Value;
        String SshPrivateKeyPath = (String)Dts.Variables["User::SshPrivateKeyPath"].Value;
        
        try
        {
            SessionOptions sessionOptions = new SessionOptions
            {
                Protocol = Protocol.Sftp,
                HostName = HostName,
                UserName = Username,
                PortNumber = PortNumber,
            };
    
            // 区分私钥认证和密码认证场景
            if(!string.IsNullOrEmpty(SshPrivateKeyPath))
            {
                sessionOptions.GiveUpSecurityAndAcceptAnySshHostKey = true;
                sessionOptions.SshPrivateKeyPath = SshPrivateKeyPath;
                sessionOptions.PrivateKeyPassphrase = Password;
            }
            else
            {
                sessionOptions.Password = Password;
            }
    
            using (Session session = new Session())
            {
                // 指向本地部署的WinSCP.exe路径
                session.ExecutablePath = @"C:\Program Files\WinSCP\WinSCP.exe";
                // 配置会话日志路径,方便排查连接、传输问题
                session.SessionLogPath = @"C:\Logs\WinSCP\sftp_transfer.log";
    
                session.Open(sessionOptions);
    
                TransferOptions transferOptions = new TransferOptions();
                transferOptions.TransferMode = TransferMode.Binary;
                // 规范化拼接本地文件路径,避免缺失分隔符导致路径错误
                string localFilePath = Path.Combine(FileLocation, FileName);
    
                TransferOperationResult transferResult;
                transferResult = session.PutFiles(localFilePath, RemoteLocation, false, transferOptions);
    
                transferResult.Check();
    
                bool fireAgain = false;
                foreach (TransferEventArgs transfer in transferResult.Transfers)
                {
                    Dts.Events.FireInformation(3, "sFTP", "Upload Succeed", transfer.FileName, 0, ref fireAgain);
                }
                Dts.TaskResult = (int)ScriptResults.Success;
            }
        }
        catch (Exception e)
        {
            Dts.Events.FireError(18, "sFTP Upload Error: {" + HostName + "}", e.ToString(), "", 0);
            Dts.TaskResult = (int)ScriptResults.Failure;
        }
    }
    
  4. 部署前验证
    • 提前创建会话日志目录,给服务运行账号授予写入权限,运行失败时直接查看WinSCP会话日志即可定位具体错误点
    • 在服务器上手动使用配置的账号信息测试SFTP连接,确认网络连通性、账号权限、远程路径均正常
    • 本地调试时将Visual Studio中SSIS项目的Run64BitRuntime属性与服务器生产环境的运行时配置对齐,调试通过后再部署包

内容的提问来源于stack exchange,提问作者Ricardo Ferreira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:18:13