Reputation: 1699
So, I´m following this Google´s step-by-step for Google Drive API Rest in C#. I basically wanted to list my files in my Google Drive from my console C# application.
I created the Oauth2 credential, downloaded the json file, imported into my Visual Studio project, installed Google Drive APIs v3 using the NuGet manager, copied and pasted the C# code (below). But I keep getting error {"Access is denied"} (in the innerException) in my GoogleWebAuthorizationBroker.AuthorizeAsync() method. Can anyone please help me?
My C# Code:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Drive_API_Quickstart__2nd_attempt_
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-dotnet-quickstart.json
static string[] Scopes = { DriveService.Scope.DriveReadonly };
static string ApplicationName = "Drive API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/drive-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Drive API service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define parameters of request.
FilesResource.ListRequest listRequest = service.Files.List();
listRequest.PageSize = 10;
listRequest.Fields = "nextPageToken, files(id, name)";
// List files.
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute()
.Files;
Console.WriteLine("Files:");
if (files != null && files.Count > 0)
{
foreach (var file in files)
{
Console.WriteLine("{0} ({1})", file.Name, file.Id);
}
}
else
{
Console.WriteLine("No files found.");
}
Console.Read();
}
}
}
The debug error:
System.AggregateException was unhandled
HResult=-2146233088
Message=One or more errors occurred.
Source=mscorlib
StackTrace:
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at Drive_API_Quickstart__2nd_attempt_.Program.Main(String[] args) in W:\Adriano\Visual Studio\Google Drive\Drive API Quickstart (2nd attempt)\Drive API Quickstart (2nd attempt)\Program.cs:line 34
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
ErrorCode=5
HResult=-2147467259
Message=Access is denied
NativeErrorCode=5
Source=System
StackTrace:
at System.Net.HttpListener.AddAllPrefixes()
at System.Net.HttpListener.Start()
at Google.Apis.Auth.OAuth2.LocalServerCodeReceiver.StartListener()
at Google.Apis.Auth.OAuth2.LocalServerCodeReceiver.<ReceiveCodeAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.AuthorizationCodeInstalledApp.<AuthorizeAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.<AuthorizeAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.<AuthorizeAsync>d__1.MoveNext()
InnerException:
Upvotes: 1
Views: 3938
Reputation: 11
I faced the same issue with a windows desktop program. When I rsn it from the debugger it didn't work. Then I solved the issue by using the "Run as Administrator " option. It popped up with the google account selection window. Here is my code. Make sure you select the auth key properly.
void GoogleThread()
{
try
{
//Scopes for use with the Google Drive API
string[] scopes = new string[] {
DriveService.Scope.DriveFile};
var clientId = "Create auth0 Id and copy here"; // From https://console.developers.google.com
var clientSecret = ""; // From https://console.developers.google.com
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
GoogleWebAuthorizationBroker.Folder = "Drive.Sample";
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
},
scopes,
"Admin",
CancellationToken.None,
new FileDataStore("Daimto.GoogleDrive.Auth.Store")).Result;
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",
});
uploadFile(service, "d:\\bmjo\\EastManTemp.xml", "0B1HV_LVO8x0zSWFrRkE2LVFUQ2c");
}
catch (Exception exp)
{
MessageBox.Show(exp.Message, "Error");
}
}
// tries to figure out the mime type of the file.
private static string GetMimeType(string fileName)
{
string mimeType = "application/unknown";
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}
public static File uploadFile(DriveService _service, string _uploadFile, string _parent)
{
if (System.IO.File.Exists(_uploadFile))
{
File body = new File();
body.Title = System.IO.Path.GetFileName(_uploadFile);
body.Description = "File uploaded by Diamto Drive Sample";
body.MimeType = GetMimeType(_uploadFile);
body.Parents = new List<ParentReference>();// { new ParentReference() { Id = _parent } };
body.Parents.Add(new ParentReference() { Id = _parent });
// File's content.
byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.InsertMediaUpload request = _service.Files.Insert(body, stream, GetMimeType(_uploadFile));
request.Upload();
return request.ResponseBody;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
return null;
}
}
else
{
Console.WriteLine("File does not exist: " + _uploadFile);
return null;
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(GoogleThread));
thread.Start();
}
Upvotes: 1
Reputation: 322
Have you tried this implementing authorization correctly?
The document quickstart that you mentioned has some notes regarding auth:
Notes
Authorization information is stored on the file system, so subsequent executions will not prompt for authorization. The authorization flow in this example is designed for a command-line application. For information on how to perform authorization in a web application, see the web applications section of the library's OAuth 2.0 guide.
Also, kindly follow the steps on what this document about OAuth :
To find the redirect URIs for your OAuth 2.0 credentials, do the following:
1.) Open the Credentials page in the API Console.
2.) If you haven't done so already, create your OAuth 2.0 credentials by clicking Create credentials > OAuth client ID.
3.) After you create your credentials, view or edit the redirect URLs by clicking the client ID (for a web application) in the OAuth 2.0 client IDs section.
You might be missing those steps. You also might have the incorrect file for the client_secrets.json. May I ask if how did you actually downloaded the file?
Upvotes: 1