This project is read-only.

Using BeginOpenWrite

Dec 16, 2013 at 12:14 PM
I really like this library it's really good and the documentation is great.
I am trying to use it in a script to deploy a zip on two different servers and I got stuck when I try to use BeginOpenWrite on both servers asynchronously . I receive:

System.InvalidOperationException occurred
HResult=-2146233079
Message=The specified IAsyncResult could not be located.
Source=System.Net.FtpClient
StackTrace:
   at System.Net.FtpClient.FtpClient.GetAsyncDelegate[T](IAsyncResult ar) in c:\Users\Afik\Downloads\netftp-b66429c4bceff38772e139409de00f7cf184d402\System.Net.FtpClient\FtpClient.cs:line 553
InnerException:

Any idea?
Dec 16, 2013 at 12:39 PM
The IAsyncResult is being lost somewhere. You need to keep the IAsyncReuslt objects from each call to BeginOpenWrite() and pass those to EndOpenWrite() when you're done. If that's not the case I'll need to see some code, how you're using System.Net.FtpClient.
Dec 16, 2013 at 12:52 PM
I pass it but it still fails.

it fails in:
    protected T GetAsyncDelegate<T>(IAsyncResult ar) {
        T func;

        lock (m_asyncmethods)
        {
            //Debugger.Launch();
__ if (!m_asyncmethods.ContainsKey(ar))
                throw new InvalidOperationException("The specified IAsyncResult could not be located.");__

            if (!(m_asyncmethods[ar] is T)) {
                StackTrace st = new StackTrace(1);

                throw new InvalidCastException("The AsyncResult cannot be matched to the specified delegate. " +
                    string.Format("Are you sure you meant to call {0} and not another method?",
                    st.GetFrame(0).GetMethod().Name)
                );
            }

            func = (T)m_asyncmethods[ar];
            m_asyncmethods.Remove(ar);
        }

        return func;
    }

this is how I use it
   public class MultiThreadedUploader 
{
    private static MultiThreadedUploader _instance;
    public Dictionary<string, int> _currnetJobs;


    private MultiThreadedUploader()
    {
        _currnetJobs = new Dictionary<string, int>();
    }

    public static MultiThreadedUploader Instance
    {
        get { return _instance ?? (_instance = new MultiThreadedUploader()); }
    }

    public bool CurrentlyWorking()
    {
        lock (_currnetJobs)
        {
            return _currnetJobs.Any(job => job.Value > 0);
        }
    }

    public void Run()
    {
        while (UploadingQueue.QueueNotEmpty())
        {
            foreach (var currnetJob in UploadingQueue.Queues)
            {
                FileUploadTask task;
                while (currnetJob.Value.TryDequeue(out task))
                {
                    if (!_currnetJobs.ContainsKey(currnetJob.Key))
                        _currnetJobs.Add(currnetJob.Key,0);

                    _currnetJobs[currnetJob.Key]++;
                    Console.WriteLine("Uploading file {0} To {1}.", task.GetShortFileName, task.Host.Hostname);
                    task.BeginFileUpload();
                }
            }
        }

        while (CurrentlyWorking())
        {
            Thread.Sleep(100);
        }
    }
}

public class FileUploadTask
{
    public string Filename { get; set; }
    public IHost Host { get; set; }

    public string GetShortFileName
    {
        get
        {
            var f = new FileInfo(Filename);
            return f.Name;
        }
    }

    private IAsyncResult _asyncResult;

    public void BeginFileUpload()
    {
        using (var conn = new FtpClient())
        {
            conn.Host = Host.Hostname;
            conn.Credentials = new NetworkCredential(Host.User, Host.Password);
            _asyncResult = conn.BeginOpenWrite("/AfikTest/" + GetShortFileName,
                BeginFileUploadCallback, conn);
        }
    }

    private void BeginFileUploadCallback(IAsyncResult ar)
    {

        var conn = _asyncResult.AsyncState as FtpClient;
        Stream istream = null, ostream = null;
        var buf = new byte[8192];
        int read = 0;

        try
        {
            if (conn == null)
                throw new InvalidOperationException("The FtpControlConnection object is null!");
            Debugger.Launch();
            ostream = conn.EndOpenWrite(_asyncResult);
            istream = new FileStream(Filename, FileMode.Open, FileAccess.Read);

            while ((read = istream.Read(buf, 0, buf.Length)) > 0)
            {
                ostream.Write(buf, 0, read);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        finally
        {
            if (istream != null)
                istream.Close();

            if (ostream != null)
                ostream.Close();

            if (conn != null) conn.Disconnect();
        }
        MultiThreadedUploader.Instance._currnetJobs[Host.Hostname]--;
        Console.WriteLine("Finished uploading file {0} To {1}.", GetShortFileName, Host.Hostname);
    }
}
Dec 16, 2013 at 1:57 PM
Edited Dec 16, 2013 at 3:43 PM
What happens if you change:
    public void BeginFileUpload()
    {
        using (var conn = new FtpClient())
        {
            conn.Host = Host.Hostname;
            conn.Credentials = new NetworkCredential(Host.User, Host.Password);
            _asyncResult = conn.BeginOpenWrite("/AfikTest/" + GetShortFileName,
                BeginFileUploadCallback, conn);
        }
    }
To:
    public void BeginFileUpload()
    {
       var conn = new FtpClient();
            conn.Host = Host.Hostname;
            conn.Credentials = new NetworkCredential(Host.User, Host.Password);
            _asyncResult = conn.BeginOpenWrite("/AfikTest/" + GetShortFileName,
                BeginFileUploadCallback, conn);
    }
The problem, I believe, is the connection object is being disposed because of the using statement, which clears out the internal collection of IAsyncResult's. My example code for this method is poor because it actually blocks while the asynchronous code takes place so it stops the connection object from being disposed early.
Marked as answer by Afiku on 12/16/2013 at 7:41 AM
Dec 16, 2013 at 2:11 PM
I've added comments to the examples to point out the potential problem here and I've added a check to the internal GetAsyncMethod() call to see if the FtpClient object has been disposed. If it has an ObjectDisposed() exception is thrown. While these won't fix the problem, they will help figure out async programming errors, assuming that is indeed the problem with the code.
Dec 16, 2013 at 3:41 PM
Worked! It was so normal for me that the using should be there that I missed it.

Thanks!
Dec 16, 2013 at 3:44 PM
No problem