Hi,

I have an annoying problem with a FTP upload. I want to upload a few files to a FTP Server. This FTP Server is an IIS FTP 7.5 server with required SSL and basic authentication.
I wrote the code below and all works fine on my local development computer. But if I try to run the code against a remote FTP server the first call works fine, but always the second one fails with the following error: "Authentication failed because the remote party has closed the transport stream."

I tried so much but nothing works for me. Any suggestions?

Code:
internal class FtpAsynchronous
{
        /// <summary>
        /// Asynchronouses the upload.
        /// </summary>
        /// <param name="baseUrl">The base URL.</param>
        /// <param name="filename">The filename.</param>
        /// <param name="state">The state.</param>
        internal void AsynchronousUpload(Uri baseUrl, string filename, FtpState state)
        {
            Uri url = baseUrl;

            // if a filename is available use it a relative url
            if (!String.IsNullOrEmpty(filename))
            {
                url = new Uri(baseUrl, filename);
            }

            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);

            // we want to upload a file
            request.Method = WebRequestMethods.Ftp.UploadFile;

            // enable SSL
            request.EnableSsl = true;

            // do not reuse connection
            request.KeepAlive = false;

            // set ftp credentials
            request.Credentials = new NetworkCredential(Settings.Default.FtpUsername, Settings.Default.FtpPassword);

            // Store the request in the object that we pass into the
            // asynchronous operations.
            state.Request = request;

            // Get the event to wait on.
            ManualResetEvent waitObject = state.OperationComplete;

            // Asynchronously get the stream for the file contents.
            request.BeginGetRequestStream(EndGetStreamCallback, state);

            // Block the current thread until all operations are complete.
            waitObject.WaitOne();

            // The operations either completed or threw an exception.
            if (state.OperationException != null)
            {
                throw state.OperationException;
            }
        }

        /// <summary>
        /// Ends the get stream callback.
        /// </summary>
        /// <param name="ar">The ar.</param>
        private static void EndGetStreamCallback(IAsyncResult ar)
        {
            FtpState state = (FtpState)ar.AsyncState;

            // End the asynchronous call to get the request stream.
            try
            {
                state.Request.ContentLength = state.Content.Length;

                Stream requestStream = state.Request.EndGetRequestStream(ar);

                requestStream.Write(state.Content, 0, state.Content.Length);               

                // IMPORTANT: Close the request stream before sending the request.
                requestStream.Close();

                // Asynchronously get the response to the upload request.
                state.Request.BeginGetResponse(EndGetResponseCallback, state);
            }
            catch (Exception e)
            {
                // Return exceptions to the main application thread.
                state.OperationException = e;
                state.OperationComplete.Set();
            }
        }

        /// <summary>
        /// Ends the get response callback.
        /// </summary>
        /// <param name="ar">The ar.</param>
        private static void EndGetResponseCallback(IAsyncResult ar)
        {
            FtpState state = (FtpState)ar.AsyncState;
            try
            {
                FtpWebResponse response = (FtpWebResponse)state.Request.EndGetResponse(ar);
                response.Close();
                state.StatusDescription = response.StatusDescription;
                
                // Signal the main application thread that
                // the operation is complete.
                state.OperationComplete.Set();
            }
            catch (Exception e)
            {
                // Return exceptions to the main application thread.
                state.OperationException = e;
                state.OperationComplete.Set();
            }
}


public class FtpState
{
        /// <summary>
        /// thread notifier
        /// </summary>
        private readonly ManualResetEvent wait;

        /// <summary>
        /// Initializes a new instance of the <see cref="FtpState"/> class.
        /// </summary>
        public FtpState()
        {
            this.OperationException = null;
            this.wait = new ManualResetEvent(false);
        }

        /// <summary>
        /// Gets the operation complete.
        /// </summary>
        /// <value>The operation complete.</value>
        public ManualResetEvent OperationComplete
        {
            get { return this.wait; }
        }

        /// <summary>
        /// Gets or sets the request.
        /// </summary>
        /// <value>The request.</value>
        public FtpWebRequest Request { get; set; }

        /// <summary>
        /// Gets or sets the name of the file.
        /// </summary>
        /// <value>The name of the file.</value>
        public string FileName { get; set; }

        /// <summary>
        /// Gets or sets the operation exception.
        /// </summary>
        /// <value>The operation exception.</value>
        public Exception OperationException { get; set; }

        /// <summary>
        /// Gets or sets the status description.
        /// </summary>
        /// <value>The status description.</value>
        public string StatusDescription { get; set; }

        /// <summary>
        /// Gets or sets the content.
        /// </summary>
        /// <value>The content.</value>
        internal byte[] Content { get; set; }
}
Thats the basics and here comes the final call:
Code:
foreach (var document in documents)
{
   FtpAsynchronous ftp = new FtpAsynchronous();
   ftp.AsynchronousUpload(new Uri(Settings.Default.FtpBaseUrl), document.FtpFilename, new FtpState { FileName = document.Name, Content = document.Content });
}
I believe there is a problem with the SSL on the IIS FTP 7.5 but I can not find anything. So maybe I made a mistake in the code.