chr0m1ng
chr0m1ng

Reputation: 415

Upload image to a FTP Server using PCL Xamarin Forms

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.

Upvotes: 2

Views: 3218

Answers (1)

chr0m1ng
chr0m1ng

Reputation: 415

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.

Upvotes: 2

Related Questions