Upload image to a FTP Server using PCL Xamarin Forms

Chr0m1ngChr0m1ng BRMember ✭✭
edited March 2017 in Xamarin.Forms

Hi, i'm new on Xamarin and C# world and i'm trying to upload an Image to a FTP Server. I saw the FtpWebRequest class to do this but i'm not getting it right, i don't know how to inject plataform specific code and i don't even know what it really mean, already watched this video (https://www.youtube.com/watch?feature=player_embedded&v=yduxdUCKU1c) but i don't see how to use this to create the FtpWebRequest class and upload the image.

I Saw this code(here: https://forums.xamarin.com/discussion/9052/strange-behaviour-with-ftp-upload) to send a picture and i'm unable to use it.

    public void sendAPicture(string picture)
    {

        string ftpHost = "xxxx";

        string ftpUser = "yyyy";

        string ftpPassword = "zzzzz";

        string ftpfullpath = "ftp://myserver.com/testme123.jpg";

        FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpfullpath);

        //userid and password for the ftp server  

        ftp.Credentials = new NetworkCredential(ftpUser, ftpPassword);

        ftp.KeepAlive = true;
        ftp.UseBinary = true;
        ftp.Method = WebRequestMethods.Ftp.UploadFile;

        FileStream fs = File.OpenRead(picture);

        byte[] buffer = new byte[fs.Length];
        fs.Read(buffer, 0, buffer.Length);

        fs.Close();

        Stream ftpstream = ftp.GetRequestStream();
        ftpstream.Write(buffer, 0, buffer.Length);
        ftpstream.Close();
        ftpstream.Flush();

        //  fs.Flush();

    }

I don't have a type FileStream, WebRequestMethods and File, also my FtpWebRequest class doens't have "KeepAlive", "UseBinary" and "GetRequestStream" methods, and my Stream class doesn't have "Close" method.

My FtpWebRequest Class:

public sealed class FtpWebRequest : WebRequest
{
    public override string ContentType
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public override WebHeaderCollection Headers
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public override string Method
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public override Uri RequestUri
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public override void Abort()
    {
        throw new NotImplementedException();
    }

    public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)
    {
        throw new NotImplementedException();
    }

    public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
    {
        throw new NotImplementedException();
    }

    public override Stream EndGetRequestStream(IAsyncResult asyncResult)
    {
        throw new NotImplementedException();
    }

    public override WebResponse EndGetResponse(IAsyncResult asyncResult)
    {
        throw new NotImplementedException();
    }
}

(I know, i didn't wrote anything there, just pressed ctrl + . because i don't know what to write there)

Does anyone can provide me a full sample of a FtpWebRequest class? i only find the class in use like this one above.

Best Answer

  • Chr0m1ngChr0m1ng BR ✭✭
    Accepted Answer

    Ok, I just figured out how to do this and I'll show how I did, I don't really know if is the better and right way to do, but it works.

    First I had to create a Interface Class Called IFtpWebRequest on my forms project, which contains exactly this:

    namespace Contato_Vistoria
    {
            public interface IFtpWebRequest
            {
                string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "");
            }
    }
    

    Then, inside my iOS/droid project i had to create a class caled FTP that implements IFtpWebRequest and inside that class i wrote the upload function(I'm using another one now), here's the ENTIRE FTP class:

    using System;
    using System.IO;
    using System.Net;
    using Contato_Vistoria.Droid; //My droid project
    
    [assembly: Xamarin.Forms.Dependency(typeof(FTP))] //You need to put this on iOS/droid class or uwp/etc if you wrote
    namespace Contato_Vistoria.Droid
    {
        class FTP : IFtpWebRequest
        {
            public FTP() //I saw on Xamarin documentation that it's important to NOT pass any parameter on that constructor
            {
            }
    
            /// Upload File to Specified FTP Url with username and password and Upload Directory if need to upload in sub folders
            ///Base FtpUrl of FTP Server
            ///Local Filename to Upload
            ///Username of FTP Server
            ///Password of FTP Server
            ///[Optional]Specify sub Folder if any
            /// Status String from Server
            public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
            {
                try
                {
    
                    string PureFileName = new FileInfo(fileName).Name;
                    String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
                    FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
                    req.Proxy = null;
                    req.Method = WebRequestMethods.Ftp.UploadFile;
                    req.Credentials = new NetworkCredential(userName, password);
                    req.UseBinary = true;
                    req.UsePassive = true;
                    byte[] data = File.ReadAllBytes(fileName);
                    req.ContentLength = data.Length;
                    Stream stream = req.GetRequestStream();
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                    FtpWebResponse res = (FtpWebResponse)req.GetResponse();
                    return res.StatusDescription;
    
                }
                catch(Exception err)
                {
                    return err.ToString();
                }
            }
        }
    }
    

    It's pretty much the same on my iOS project, but I'll post it anyway to help those like me that don't know too much and need to see full examples of how to do it. Here it is:

    using System;
    using System.Net;
    using System.IO;
    //Only thing that changes to droid class is that \/
    using Foundation;
    using UIKit;
    using Contato_Vistoria.iOS;
    
    
    [assembly: Xamarin.Forms.Dependency(typeof(FTP))]
    namespace Contato_Vistoria.iOS  //   /\
    {
        class FTP : IFtpWebRequest
        {
            public FTP()
            {
    
            }
    
            /// Upload File to Specified FTP Url with username and password and Upload Directory if need to upload in sub folders
            ///Base FtpUrl of FTP Server
            ///Local Filename to Upload
            ///Username of FTP Server
            ///Password of FTP Server
            ///[Optional]Specify sub Folder if any
            /// Status String from Server
            public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
            {
                try
                {
                    string PureFileName = new FileInfo(fileName).Name;
                    String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
                    FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
                    req.Proxy = null;
                    req.Method = WebRequestMethods.Ftp.UploadFile;
                    req.Credentials = new NetworkCredential(userName, password);
                    req.UseBinary = true;
                    req.UsePassive = true;
                    byte[] data = File.ReadAllBytes(fileName);
                    req.ContentLength = data.Length;
                    Stream stream = req.GetRequestStream();
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                    FtpWebResponse res = (FtpWebResponse)req.GetResponse();
                    return res.StatusDescription;
    
                }
                catch (Exception err)
                {
                    return err.ToString();
                }
            }
        }
    }
    

    Finally, back on my Xamarin Forms project, this is how i called the function. Inside a simple click event from a Button on my GUI:

        protected async void btConcluidoClicked(object sender, EventArgs e)
        {
            if (Device.OS == TargetPlatform.Android || Device.OS == TargetPlatform.iOS)
                await DisplayAlert("Upload", DependencyService.Get<IFtpWebRequest>().upload("ftp://ftp.swfwmd.state.fl.us", ((ListCarImagesViewModel)BindingContext).Items[0].Image, "Anonymous", "[email protected]", "/pub/incoming"), "Ok");
    
            await Navigation.PopAsync();
        }
    

    To call the function you need to write "DependencyService.Get().YourFunction(Parameters of the function)", to be more specific.

    And that's how I did it, hope I can help someone, anyway thanks for the help @Velocity.

Answers

  • VelocityVelocity NZMember ✭✭✭

    Thanks for your Q. Actually, this is not so much a Xamarin-specific question but rather a question of is there an existing package/library available in .NET to do this sort of thing.

    You probably want something like this.

  • Chr0m1ngChr0m1ng BRMember ✭✭

    @Velocity said:
    Thanks for your Q. Actually, this is not so much a Xamarin-specific question but rather a question of is there an existing package/library available in .NET to do this sort of thing.

    You probably want something like this.

    Actualy, i want to use FtpWebRequest but i don't know how to do a DI. Also, i'm unable to install that library you gave me via Nuget.

  • Chr0m1ngChr0m1ng BRMember ✭✭
    Accepted Answer

    Ok, I just figured out how to do this and I'll show how I did, I don't really know if is the better and right way to do, but it works.

    First I had to create a Interface Class Called IFtpWebRequest on my forms project, which contains exactly this:

    namespace Contato_Vistoria
    {
            public interface IFtpWebRequest
            {
                string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "");
            }
    }
    

    Then, inside my iOS/droid project i had to create a class caled FTP that implements IFtpWebRequest and inside that class i wrote the upload function(I'm using another one now), here's the ENTIRE FTP class:

    using System;
    using System.IO;
    using System.Net;
    using Contato_Vistoria.Droid; //My droid project
    
    [assembly: Xamarin.Forms.Dependency(typeof(FTP))] //You need to put this on iOS/droid class or uwp/etc if you wrote
    namespace Contato_Vistoria.Droid
    {
        class FTP : IFtpWebRequest
        {
            public FTP() //I saw on Xamarin documentation that it's important to NOT pass any parameter on that constructor
            {
            }
    
            /// Upload File to Specified FTP Url with username and password and Upload Directory if need to upload in sub folders
            ///Base FtpUrl of FTP Server
            ///Local Filename to Upload
            ///Username of FTP Server
            ///Password of FTP Server
            ///[Optional]Specify sub Folder if any
            /// Status String from Server
            public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
            {
                try
                {
    
                    string PureFileName = new FileInfo(fileName).Name;
                    String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
                    FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
                    req.Proxy = null;
                    req.Method = WebRequestMethods.Ftp.UploadFile;
                    req.Credentials = new NetworkCredential(userName, password);
                    req.UseBinary = true;
                    req.UsePassive = true;
                    byte[] data = File.ReadAllBytes(fileName);
                    req.ContentLength = data.Length;
                    Stream stream = req.GetRequestStream();
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                    FtpWebResponse res = (FtpWebResponse)req.GetResponse();
                    return res.StatusDescription;
    
                }
                catch(Exception err)
                {
                    return err.ToString();
                }
            }
        }
    }
    

    It's pretty much the same on my iOS project, but I'll post it anyway to help those like me that don't know too much and need to see full examples of how to do it. Here it is:

    using System;
    using System.Net;
    using System.IO;
    //Only thing that changes to droid class is that \/
    using Foundation;
    using UIKit;
    using Contato_Vistoria.iOS;
    
    
    [assembly: Xamarin.Forms.Dependency(typeof(FTP))]
    namespace Contato_Vistoria.iOS  //   /\
    {
        class FTP : IFtpWebRequest
        {
            public FTP()
            {
    
            }
    
            /// Upload File to Specified FTP Url with username and password and Upload Directory if need to upload in sub folders
            ///Base FtpUrl of FTP Server
            ///Local Filename to Upload
            ///Username of FTP Server
            ///Password of FTP Server
            ///[Optional]Specify sub Folder if any
            /// Status String from Server
            public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
            {
                try
                {
                    string PureFileName = new FileInfo(fileName).Name;
                    String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
                    FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
                    req.Proxy = null;
                    req.Method = WebRequestMethods.Ftp.UploadFile;
                    req.Credentials = new NetworkCredential(userName, password);
                    req.UseBinary = true;
                    req.UsePassive = true;
                    byte[] data = File.ReadAllBytes(fileName);
                    req.ContentLength = data.Length;
                    Stream stream = req.GetRequestStream();
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                    FtpWebResponse res = (FtpWebResponse)req.GetResponse();
                    return res.StatusDescription;
    
                }
                catch (Exception err)
                {
                    return err.ToString();
                }
            }
        }
    }
    

    Finally, back on my Xamarin Forms project, this is how i called the function. Inside a simple click event from a Button on my GUI:

        protected async void btConcluidoClicked(object sender, EventArgs e)
        {
            if (Device.OS == TargetPlatform.Android || Device.OS == TargetPlatform.iOS)
                await DisplayAlert("Upload", DependencyService.Get<IFtpWebRequest>().upload("ftp://ftp.swfwmd.state.fl.us", ((ListCarImagesViewModel)BindingContext).Items[0].Image, "Anonymous", "[email protected]", "/pub/incoming"), "Ok");
    
            await Navigation.PopAsync();
        }
    

    To call the function you need to write "DependencyService.Get().YourFunction(Parameters of the function)", to be more specific.

    And that's how I did it, hope I can help someone, anyway thanks for the help @Velocity.

  • SP41KSP41K Member ✭✭
    edited June 2018

    Thanks!

  • @Chr0m1ng said:
    Ok, I just figured out how to do this and I'll show how I did, I don't really know if is the better and right way to do, but it works.

    First I had to create a Interface Class Called IFtpWebRequest on my forms project, which contains exactly this:

    namespace Contato_Vistoria
    {
    public interface IFtpWebRequest
    {
    string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "");
    }
    }

    Then, inside my iOS/droid project i had to create a class caled FTP that implements IFtpWebRequest and inside that class i wrote the upload function(I'm using another one now), here's the ENTIRE FTP class:

    using System;
    using System.IO;
    using System.Net;
    using Contato_Vistoria.Droid; //My droid project

    [assembly: Xamarin.Forms.Dependency(typeof(FTP))] //You need to put this on iOS/droid class or uwp/etc if you wrote
    namespace Contato_Vistoria.Droid
    {
    class FTP : IFtpWebRequest
    {
    public FTP() //I saw on Xamarin documentation that it's important to NOT pass any parameter on that constructor
    {
    }

    /// Upload File to Specified FTP Url with username and password and Upload Directory if need to upload in sub folders
    ///Base FtpUrl of FTP Server
    ///Local Filename to Upload
    ///Username of FTP Server
    ///Password of FTP Server
    ///[Optional]Specify sub Folder if any
    /// Status String from Server
    public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
    {
    try
    {

    string PureFileName = new FileInfo(fileName).Name;
    String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
    FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
    req.Proxy = null;
    req.Method = WebRequestMethods.Ftp.UploadFile;
    req.Credentials = new NetworkCredential(userName, password);
    req.UseBinary = true;
    req.UsePassive = true;
    byte[] data = File.ReadAllBytes(fileName);
    req.ContentLength = data.Length;
    Stream stream = req.GetRequestStream();
    stream.Write(data, 0, data.Length);
    stream.Close();
    FtpWebResponse res = (FtpWebResponse)req.GetResponse();
    return res.StatusDescription;

    }
    catch(Exception err)
    {
    return err.ToString();
    }
    }
    }
    }

    It's pretty much the same on my iOS project, but I'll post it anyway to help those like me that don't know too much and need to see full examples of how to do it. Here it is:

    using System;
    using System.Net;
    using System.IO;
    //Only thing that changes to droid class is that \/
    using Foundation;
    using UIKit;
    using Contato_Vistoria.iOS;

    [assembly: Xamarin.Forms.Dependency(typeof(FTP))]
    namespace Contato_Vistoria.iOS // /\
    {
    class FTP : IFtpWebRequest
    {
    public FTP()
    {

    }

    /// Upload File to Specified FTP Url with username and password and Upload Directory if need to upload in sub folders
    ///Base FtpUrl of FTP Server
    ///Local Filename to Upload
    ///Username of FTP Server
    ///Password of FTP Server
    ///[Optional]Specify sub Folder if any
    /// Status String from Server
    public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
    {
    try
    {
    string PureFileName = new FileInfo(fileName).Name;
    String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
    FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
    req.Proxy = null;
    req.Method = WebRequestMethods.Ftp.UploadFile;
    req.Credentials = new NetworkCredential(userName, password);
    req.UseBinary = true;
    req.UsePassive = true;
    byte[] data = File.ReadAllBytes(fileName);
    req.ContentLength = data.Length;
    Stream stream = req.GetRequestStream();
    stream.Write(data, 0, data.Length);
    stream.Close();
    FtpWebResponse res = (FtpWebResponse)req.GetResponse();
    return res.StatusDescription;

    }
    catch (Exception err)
    {
    return err.ToString();
    }
    }
    }
    }

    Finally, back on my Xamarin Forms project, this is how i called the function. Inside a simple click event from a Button on my GUI:

        protected async void btConcluidoClicked(object sender, EventArgs e)
        {
            if (Device.OS == TargetPlatform.Android || Device.OS == TargetPlatform.iOS)
                await DisplayAlert("Upload", DependencyService.Get<IFtpWebRequest>().upload("ftp://ftp.swfwmd.state.fl.us", ((ListCarImagesViewModel)BindingContext).Items[0].Image, "Anonymous", "[email protected]", "/pub/incoming"), "Ok");
    
            await Navigation.PopAsync();
        }
    

    To call the function you need to write "DependencyService.Get().YourFunction(Parameters of the function)", to be more specific.

    And that's how I did it, hope I can help someone, anyway thanks for the help @Velocity.

    i have used it the same way as you did in my xamarin forms application to upload image to one of the directory on filezilla server but ultimately i got an error with a response code 403 forbidden, i have tried some other ways to do so but still didn't get success in uploading image to my server.

Sign In or Register to comment.