Search code examples
c#asp.netasp.net-mvcgoogle-drive-apigoogle-api-dotnet-client

Problems with files downloading from Google Drive Api using asp.net mvc


I can download files successfully on local server but after deployment I can't its just keep loading without downloads

  <a href="~/Home/DownloadFile/@item.Id">Download</a>

HomeController.cs

 public void DownloadFile(string id)
    {
        string FilePath = DownloadGoogleFile(id);
       
        Response.AddHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(FilePath));
        Response.WriteFile(System.Web.Hosting.HostingEnvironment.MapPath("/GoogleDriveFiles/" + Path.GetFileName(FilePath)));
        Response.End();
        Response.Flush();
    }
    static string DownloadGoogleFile(string fileId)
    {
        Google.Apis.Drive.v3.DriveService service = GetService();

        string FolderPath = System.Web.Hosting.HostingEnvironment.MapPath("/GoogleDriveFiles/");
        Google.Apis.Drive.v3.FilesResource.GetRequest request = service.Files.Get(fileId);

        string FileName = request.Execute().Name;
        string FilePath = System.IO.Path.Combine(FolderPath, FileName);

        MemoryStream stream1 = new MemoryStream();
        request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
        {
            switch (progress.Status)
            {
                case DownloadStatus.Downloading:
                    {
                        Console.WriteLine(progress.BytesDownloaded);
                        break;
                    }
                case DownloadStatus.Completed:
                    {
                        Console.WriteLine("Download complete.");
                        SaveStream(stream1, FilePath);
                        break;
                    }
            }
        };
        request.Download(stream1);
        return FilePath;
    }

   
   public static Google.Apis.Drive.v3.DriveService GetService()
    {
        var CSPath = System.Web.Hosting.HostingEnvironment.MapPath("~/");
        UserCredential credential;
        using (var stream = new FileStream(Path.Combine(CSPath, "client_secret.json"), FileMode.Open, FileAccess.Read))
        {
            
            String FilePath = Path.Combine(CSPath, "DriveServiceCredentials.json");

            credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                GoogleClientSecrets.Load(stream).Secrets,
                Scopes,
                "user",
                CancellationToken.None,
                new FileDataStore(FilePath, true)).Result;
        }

        Google.Apis.Drive.v3.DriveService service = new Google.Apis.Drive.v3.DriveService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = "GoogleDriveRestAPI-v3",
        });

        return service;
    }

What I should change? I'm trying to get the file from google it self not from the browser is SSL certificate and secure the web has some thing with this because my web is not secure right now ?


Solution

  • When authenticating to Google there is a difference between an installed application and a web application. Installed Applications can open the authorization window in the browser on the current machine, Web applications need to open the web browser for the authorization on the users machine. GoogleWebAuthorizationBroker.AuthorizeAsync Is designed for use with installed applications. It will open the web browser for authentication and authorization on the server which wont work.

    For a web application you should be using GoogleAuthorizationCodeFlow

    using System;
    using System.Web.Mvc;
    
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Auth.OAuth2.Flows;
    using Google.Apis.Auth.OAuth2.Mvc;
    using Google.Apis.Drive.v2;
    using Google.Apis.Util.Store;
    
    namespace Google.Apis.Sample.MVC4
    {
        public class AppFlowMetadata : FlowMetadata
        {
            private static readonly IAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
                    {
                        ClientSecrets = new ClientSecrets
                        {
                            ClientId = "PUT_CLIENT_ID_HERE",
                            ClientSecret = "PUT_CLIENT_SECRET_HERE"
                        },
                        Scopes = new[] { DriveService.Scope.Drive },
                        DataStore = new FileDataStore("Drive.Api.Auth.Store")
                    });
    
            public override string GetUserId(Controller controller)
            {
                // In this sample we use the session to store the user identifiers.
                // That's not the best practice, because you should have a logic to identify
                // a user. You might want to use "OpenID Connect".
                // You can read more about the protocol in the following link:
                // https://developers.google.com/accounts/docs/OAuth2Login.
                var user = controller.Session["user"];
                if (user == null)
                {
                    user = Guid.NewGuid();
                    controller.Session["user"] = user;
                }
                return user.ToString();
    
            }
    
            public override IAuthorizationCodeFlow Flow
            {
                get { return flow; }
            }
        }
    }
    

    See full sample here