Bir müşterimizin SFTP download yaptığı veri sağlayıcı SFTP servisini yenilemiş. Mevcut kod 2007'den beri güncellenmeyen Tamir.SharpSSH.DLL'i kullanıyordu. Malesef DLL yeni servisle çalışmadı, "Tamir.SharpSsh.jsch.JSchException: Algorithm negotiation fail" hatası verdi. Hatayla ilgili internette bulduğum çözümlerden hiçbiri malesef çalışmadı.
Forum sayfalarında yaptığım araştırmadan SSH.NET'in tavsiye edildiğini gördüm. SSH.NET'in DLL'sini direk AX içinden referanslara ekleyip kullanmaya kalktığımda malesef download metodunda opsiyonel olan parametrenin X++'a gelirken zorunlu olduğunu ve daha da kötüsü bu paremetrenin X++ tarafından desteklenmeyen Action<ulong> türü olduğunu gördüm. Önce bir blogda gördüğüm çözümü denedim, metodu overload etmeyi öneriyordu, SSH.NET open source bir library olduğu için yapılabilir bir çözüm gibi geldi, ancak derlemede bir takım hatalar aldım ve hatalarla uğraşmaktansa SSH.NET DLL'yi kullanan bir DLL yazmaya karar verdim. Bu hem daha kolay olacaktı, hem de SSH.NET'in yeni bir versiyonu çıktığında güncellemek için tekrar kod düzenleme ve derleme gerekmeyecekti.
Aşağıdaki C# kodunu Dynamics 365 F&O için yazılmış bir blog sayfasındaki kodu biraz değiştirerek yazdım:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Renci.SshNet;
using System.IO;
namespace SSHNet2
{
public class SSHNet2
{
public SftpClient sftpClient;
public void OpenSFTPConnection(string host, int port, string username, string password)
{
if (this.sftpClient == null)
{
this.sftpClient = new Renci.SshNet.SftpClient(host, port, username, password);
}
if (!this.sftpClient.IsConnected)
{
this.sftpClient.Connect();
}
}
public List<string> GetDirectories(string path)
{
return this.sftpClient.ListDirectory(path).Select(n => n.Name).ToList();
}
public void MoveFile(string sourcePath, string destinationPath, bool isPosix)
{
this.sftpClient.RenameFile(sourcePath, destinationPath, isPosix);
}
public void DeleteFile(string sourcePath)
{
this.sftpClient.DeleteFile(sourcePath);
}
public Stream DownloadFile(string sourcePath)
{
var memoryStream = new MemoryStream();
this.sftpClient.DownloadFile(sourcePath, memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
}
}
Oluşturduğum DLL'yi ve SSH.NET'in kendi DLL'sini AX klasörlerine kopyalayıp aşağıdaki kodla SFTP sorunumu çözmüş oldum:
System.IO.StreamReader streamReader;
System.IO.StreamWriter streamWriter;
SSHNet2.SSHNet2 sftp = new SSHNet2.SSHNet2();
System.IO.Stream stream;
sftp.OpenSFTPConnection(_RemoteAddress,any2int(_RemotePort), _RemoteUser, _RemotePassword);
stream = sftp.DownloadFile(_RemoteFileName);
streamReader = new System.IO.StreamReader(stream);
streamWriter = new System.IO.StreamWriter("c:\test\test.txt");
streamWriter.Write(_StreamReader.ReadToEnd());
streamWriter.Flush();
streamWriter.Close();
streamReader.Close();