0

Thanks in Advance
I'm trying to download a file, specifically a PDF file, from firebase using C#
And it keeps throwing the exception: "The remote server returned an error: (403) Forbidden."
I have tried converting the Link to a Uri, I have tried hard-coding it to "gs://xxxxxxx.appspot.com/PDF/MyPDF.pdf"

Note The two lines added didn't help

What am I doing wrong

Here is the code:

        // ----------------------------------------------------------------------------

        private async Task download( string folder, string fileName )
        {
            FirebaseStorage storage = new FirebaseStorage( Bucket,
                 new FirebaseStorageOptions
                 {
                     AuthTokenAsyncFactory = () => Task.FromResult(
                         fireBaseAuthLink.FirebaseToken ),
                     ThrowOnCancel = true,
                 } );

            var fileRef = storage.Child( folder ).Child( fileName );
            string link = "";
            try
            {
                link = await fileRef.GetDownloadUrlAsync();
                var info = await fileRef.GetMetaDataAsync();
                processDownload( fileName, link, (int)info.Size );
            }
            catch( Exception we )
            {
                MessageBox.Show( we.Message );
            }
        }

        // ----------------------------------------------------------------------------

        private void processDownload( string finalFileName, string link, int size )
        {
            try
            {
                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create( link );
                httpRequest.Method = "GET";

                // These two lines added to try to get it to work ----------------
                httpRequest.UseDefaultCredentials = true;
                httpRequest.Proxy.Credentials =
                    System.Net.CredentialCache.DefaultCredentials;
                // ---------------------------------------------------------------

                httpRequest.ContentType = "application/pdf; encoding='utf-8'";
                HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();

                Stream httpResponseStream = httpResponse.GetResponseStream();

                // Define buffer and buffer size
                byte[] buffer = new byte[size];
                int bytesRead = 0;

                // Read from response and write to file
                FileStream fileStream = File.Create( finalFileName );
                while( ( bytesRead = httpResponseStream.Read( buffer, 0, size ) ) != 0 )
                {
                    fileStream.Write( buffer, 0, bytesRead );
                }
            }
            catch( WebException we )
            {
                MessageBox.Show( we.Message ); 
            }
        }

And The firebase rules are

rules_version = '2';
service firebase.storage {
    match /b/{bucket}/o {
        match /PDF/{allPaths=**} {
           allow get;
           allow read;
           allow write;
  }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
HemmaRoyD
  • 79
  • 1
  • 9
  • doesn't the library of `FirebaseStorage` have a download method? – Lei Yang Feb 23 '22 at 08:58
  • @LeiYang I don't know, I'm just having a break from android dev and trying out some C# – HemmaRoyD Feb 23 '22 at 09:11
  • 1
    it doesn't matter what language you use. but first you must make sure you can download same url file by browser. then use devtools to insepect possible authtication http headers, which must be added to http clinet. – Lei Yang Feb 23 '22 at 09:15
  • @LeiYang Yes, I have tried that, and the link is valid – HemmaRoyD Feb 23 '22 at 09:22
  • Even though I have changed my code to answer my question, I would still like to know how to do this automatically – HemmaRoyD Feb 23 '22 at 09:39
  • 1
    This URL can help you https://www.aspsnippets.com/questions/768849/Download-file-from-FireBase-using-C-and-VBNet-in-ASPNet/ –  Feb 23 '22 at 12:18
  • Thanks @DOTNETTeam but I get an `System.NullReferenceException: 'Object reference not set to an instance of an object.'` exception on this line `var resp = HttpContext.Current.Response;` – HemmaRoyD Feb 23 '22 at 20:55

3 Answers3

0

This is an alternate answer for those who don't actually want to download it
Simply replace the line:

processDownload( fileName, link, (int)info.Size );

WITH

System.Diagnostics.Process.Start( link );

This opens the PDF in your browser

HemmaRoyD
  • 79
  • 1
  • 9
0

Ok, after much frustration and searching I have succeeded
C# Experts, please tell me what I don't need, I'm an android developer :)

Here is the answer

        // ----------------------------------------------------------------------------

        private async Task download( string folder, string fileName )
        {
            FirebaseStorage storage = new FirebaseStorage( Bucket,
                 new FirebaseStorageOptions
                 {
                     AuthTokenAsyncFactory = () => Task.FromResult(
                         fireBaseAuthLink.FirebaseToken ),
                     ThrowOnCancel = true,
                 } );

            var fileRef = storage.Child( folder ).Child( fileName );
            string link = "";
            try
            {
                link = await fileRef.GetDownloadUrlAsync();
                var info = await fileRef.GetMetaDataAsync();
                processDownload( fileName, link, (int)info.Size );
            }
            catch( Exception we )
            {
                MessageBox.Show( we.Message );
            }
        }

        // ----------------------------------------------------------------------------

        private void processDownload( string finalFileName, string link, int size )
        {
            try
            {
                HttpWebRequest httpWebRequest =
                    (HttpWebRequest)WebRequest.Create( link );

                HttpWebResponse httpResponse = 
                    (HttpWebResponse)httpWebRequest.GetResponse();
                
                HttpContext.Current = new HttpContext(
                    new HttpRequest( link, link, "" ),
                    new HttpResponse( new StringWriter() )
                    );
                
                HttpResponse response = HttpContext.Current.Response;
                response.ClearContent();
                response.Clear();
                response.ClearHeaders();
                response.Buffer = true;
                response.ContentType = "application/pdf";
                response.AddHeader( "Content-Disposition",
                    "attachment; filename=\"" + finalFileName + "\"" );

                byte[] buffer = new byte[size];
                int bytesRead = 0;

                string userProfile = System.Environment.GetEnvironmentVariable( "USERPROFILE" );
                string downloadsFolder = userProfile + "/Downloads/";
                FileStream fileStream = File.Create( downloadsFolder + finalFileName );
                Stream httpResponseStream = httpResponse.GetResponseStream();
                while( ( bytesRead = httpResponseStream.Read( buffer, 0, size ) ) != 0 )
                {
                    fileStream.Write( buffer, 0, bytesRead );
                }
                
                fileStream.Flush();
                fileStream.Close();
                response.Flush();
                response.End();
                httpResponse.Close();
            }
            catch( WebException we )
            {
                MessageBox.Show( we.Message );
            }
        }
    }

Thanks to everyone who helped

HemmaRoyD
  • 79
  • 1
  • 9
0

Ok, what a revelation, I found this in Google Cloud Docs and modified, just a TRITE easier :/
"One Line to rule them All" :)

public void downloadFile()
{
    GoogleCredential credential = GoogleCredential.FromFile( "your-json-file-from-gcp" );
    StorageClient storageClient = StorageClient.Create( credential );

    // eg: Images/MyImage.jpg
    string objectName = "what-file-you-want-to-download-from-what-folder";
    
    // eg: "c://CallItSomethingElseIfYouWant.jpg"
    string localPath = "where-you-want-to-store-it-AND-call-it";
    
    // eg: xxxxxxxx-xxxxx.appspot.com
    string bucketName = "xxxxxxxx-xxxxx.appspot.com";
    
    FileStream fileStream = File.OpenWrite( @localPath );

    // --- The Magic Line
    storageClient.DownloadObject( bucketName, objectName, fileStream );
    // --  

    fileStream.Flush();
    fileStream.Close();
}
HemmaRoyD
  • 79
  • 1
  • 9