I'm working with the Google Drive API for the very first time and I need to download a simple txt file that has as only content a single line with a version number (like 2.5.1.0), but when I download the file and open it, I get something totally different.
Also, if I just download the file using any browser, it has the expected content, but not when I download it through my application.
I would appreciate any advice on this.
This is my code so far:
private void CheckForUpdates()
{
GoogleDrive drive = new GoogleDrive();
string url = drive.GetFileURL("current.txt");
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
string tmpPath = Path.Combine(Path.GetTempPath(), "current.txt");
request.Timeout = 5000;
WebClient response = new WebClient();
response.DownloadFile(url, tmpPath);
}
public string GetFileURL(string fileName)
{
DriveService service = GetDriveService();
// Define parameters of request.
FilesResource.ListRequest listRequest = service.Files.List();
listRequest.PageSize = 10;
listRequest.Fields = "nextPageToken, files(id, name, parents, properties, shared, webContentLink, webViewLink, fullFileExtension, capabilities)";
listRequest.Q = string.Format("(name contains '{0}')", fileName);
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute().Files;
if (files.Count > 0)
{
string url = files[0].WebContentLink;
string id = files[0].Id;
return url;
}
return "";
}
private DriveService GetDriveService()
{
UserCredential credential;
DriveService service;
using (var stream = new FileStream(_pathClave, FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
credPath = _pathResult;
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
}
// Create Drive API service.
service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
return service;
}
This is the link: https://drive.google.com/uc?id=0B3P8S21qYracclVaamM2Skp4bzA&export=download
Imports System.Net
Imports System.ComponentModel
Dim Str As IO.Stream
Dim srRead As IO.StreamReader
Dim NewVer As String = ""
Dim req As WebRequest = WebRequest.Create("WebContentLink")
Dim resp As WebResponse = req.GetResponse
Str = resp.GetResponseStream
srRead = New IO.StreamReader(Str)
NewVer = srRead.ReadToEnd.Trim
vb code worked good for me may help
Related
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 2 months ago.
My overall project is to create a spreadsheet, populate it, move it to a new location and lock it.
So far creating the sheet and populating it is fine. However, when I attempt to move the file I get the following error:
Happens at this part of the code: var getRequest = DriveService.Files.Get(fileId);
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
My code is:
static void Init()
{
UserCredential credential;
//Reading Credentials File...
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/sheets.googleapis.com-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.FromStream(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
}
// Creating Google Sheets API service...
SheetsService = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Create a Drive API service client
DriveService DriveService = new DriveService(new Google.Apis.Services.BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
}
static void CreateSheet()
{
// Create a new sheet with a single tab
string sheetName = "Test Create Sheet";
var NewSheet = new Google.Apis.Sheets.v4.Data.Spreadsheet();
NewSheet.Properties = new SpreadsheetProperties();
NewSheet.Properties.Title = sheetName;
var newSheet = SheetsService.Spreadsheets.Create(NewSheet).Execute();
SpreadsheetId = newSheet.SpreadsheetId;
Sheet = "Sheet1";
}
static void MoveSheet()
{
// Get the ID of the sheet you want to move
string sheetId = SpreadsheetId;
// Get the ID of the folder you want to move the sheet to
string folderId = "XXXXXBeNF2rG0PA6bsi89YugahH-XXXX";
// Retrieve the existing parents to remove
string fileId = sheetId;
var getRequest = DriveService.Files.Get(fileId);
getRequest.Fields = "parents";
var file = getRequest.Execute();
var previousParents = String.Join(",", file.Parents);
// Move the file to the new folder
var updateRequest =
DriveService.Files.Update(new Google.Apis.Drive.v3.Data.File(),
fileId);
updateRequest.Fields = "id, parents";
updateRequest.AddParents = folderId;
updateRequest.RemoveParents = previousParents;
//file = updateRequest.Execute();
}
It turns out I had a duplicate word (DriveService):
// Create a Drive API service client
DriveService DriveService = new DriveService(new Google.Apis.Services.BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
}
Should have been this:
// Create a Drive API service client
DriveService = new DriveService(new Google.Apis.Services.BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
}
I am now beyond that issue and have a new one in the form of:
The service drive has thrown an exception. HttpStatusCode is Forbidden. Insufficient Permission: Request had insufficient authentication scopes.
I am trying to upload a JPG from my local drive to Google Drive. I set up OAuth 2.0 Client IDs on Google Clouds APIs and Services. I added Everyone group to that folder. Also, grant full control permission.
But, it still throws the following error when I run the program.
"Exception has occurred: CLR/System.UnauthorizedAccessException An
unhandled exception of type 'System.UnauthorizedAccessException'
occurred in System.Private.CoreLib.dll: 'Access to the path
'c:\folderName' is denied.'
The error throws on the following line
using (var stream = new FileStream(filePath,
FileMode.Open))
{
// Create a new file, with metadata and stream.
request = service.Files.Create(
fileMetadata, stream, "image/jpeg");
request.Fields = "id";
request.Upload();
}
Thank you for your help.
Here is my code:
namespace DocUploader
{
class Program
{
static string[] Scopes = { DriveService.Scope.Drive };
static string ApplicationName = "App Name";
static string filePath = "c:\\folderName";
static void Main(string[] args)
{
try
{
UserCredential credential;
// Load client secrets.
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.FromStream(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
});
// Upload file photo.jpg on drive.
var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
Name = "photo.jpg"
};
FilesResource.CreateMediaUpload request;
// Create a new file on drive.
using (var stream = new FileStream(filePath,
FileMode.Open))
{
// Create a new file, with metadata and stream.
request = service.Files.Create(
fileMetadata, stream, "image/jpeg");
request.Fields = "id";
request.Upload();
}
var file = request.ResponseBody;
// Prints the uploaded file id.
Console.WriteLine("File ID: " + file.Id);
}
catch (Exception e)
{
if (e is AggregateException)
{
Console.WriteLine("Credential Not found");
}
else if (e is FileNotFoundException)
{
Console.WriteLine("File not found");
}
else
{
throw;
}
}
}
}
}
The user you are running your code from does not have access to files stored in c:\folderName.
beyond that i suspect that "c:\folderName"; is in fact the name of the folder. I dont think that the following will be able to load a FileStream for a folder.
using (var stream = new FileStream(filePath, FileMode.Open))
Upload Quickstart.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Services;
using Google.Apis.Upload;
Console.WriteLine("Hello, World!");
// Installed file credentials from google developer console.
const string credentialsJson = #"C:\Development\FreeLance\GoogleSamples\Credentials\credentials.json";
// used to store authorization credentials.
var userName = "user";
// scope of authorization needed from the user
var scopes = new[] { DriveService.Scope.Drive };
// file to upload
var filePath = #"C:\Development\FreeLance\GoogleSamples\Data\image.png";
var fileName = Path.GetFileName(filePath);
var folderToUploadTo = "root";
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromFile(credentialsJson).Secrets,
scopes,
userName,
CancellationToken.None).Result;
// Create the Drive service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Daimto Drive upload Quickstart"
});
// Upload file photo.jpg on drive.
var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
Name = fileName,
Parents = new List<string>() { folderToUploadTo }
};
var fsSource = File.OpenRead(filePath);
// Create a new file, with metadatafileName and stream.
var request = service.Files.Create(
fileMetadata, fsSource, "image/jpeg");
request.Fields = "id";
var results = await request.UploadAsync(CancellationToken.None);
if (results.Status == UploadStatus.Failed)
{
Console.WriteLine($"Error uploading file: {results.Exception.Message}");
}
// the file id of the new file we created
var fileId = request.ResponseBody?.Id;
Console.WriteLine($"fileId {fileId}");
Console.ReadLine();
code slightly altered from: How to upload to Google Drive API from memory with C#
we cannot anderstand why we upload docx-file via Google Drive API v3, it compleete success. But after we upload docx we try open file and cannot open it, thre is error in error
But when open our disk in browser (Google Chrome) and try upload docx again it opens fine, without any error.
Can you please tell what is wrong we made.
Code example
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-dotnet-quickstart.json
static string[] Scopes = { DriveService.Scope.DriveMetadata };
static string ApplicationName = "Drive API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = "";
clientSecrets.ClientSecret = "";
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecrets,
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,
});
Google.Apis.Drive.v3.Data.File fileMetadata = new Google.Apis.Drive.v3.Data.File();
// fileMetadata.Name = #"excel1.xlsx";
fileMetadata.Name = #"word22222.docx";
// fileMetadata.Name = #"present1.pptx";
// var fileStream = File.Open(#"c:\temp\present.pptx", FileMode.Open);
string fileId = string.Empty;
using (var fileStream = File.Open(#"c:\temp\word3.docx", FileMode.Open))
{
// var fileStream = File.Open(#"c:\temp\excel1.xlsx", FileMode.Open);
var fileUpload = service.Files.Create(fileMetadata, fileStream, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
// var fileUpload = service.Files.Create(fileMetadata, fileStream, "application/vnd.openxmlformats-officedocument.presentationml.presentation");
fileUpload.Fields = "id";
// var fileUpload = service.Files.Create(fileMetadata);
// fileMetadata.MimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
// var fileUpload = service.Files.Create(fileMetadata, fileStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
IUploadProgress progress = fileUpload.Upload();
if (progress.Status == UploadStatus.Failed)
{
Console.WriteLine(progress.Exception);
}
else
{
fileId = fileUpload.ResponseBody.Id;
Console.WriteLine("File ID: " + fileUpload.ResponseBody.Id);
}
}
Console.ReadKey();
var permission = new Google.Apis.Drive.v3.Data.Permission();
permission.Type = "anyone";
permission.Role = "writer";
permission.PermissionDetails = new List<PermissionDetailsData>();
var perm = service.Permissions.Create(permission, fileId);
perm.Execute();
Console.WriteLine("Premission created!");
Console.ReadKey();
Process.Start("explorer.exe", "https://docs.google.com/document/d/" + fileId + "/edit");
// Process.Start("explorer.exe", "https://docs.google.com/spreadsheets/d/" + fileId + "/edit");
// Process.Start("explorer.exe", "https://docs.google.com/presentation/d/" + fileId + "/edit");
Console.WriteLine("Redirected to browser!");
Console.ReadKey();
}
}
Consideration
According to the documentation and to my tests you cannot create a file with the metadata scope only.
Using this scope will result in a permission error. Please try to use a more restricted scope to perform this operation.
Insufficient Permission: Request had insufficient authentication scopes. [403]
Solution
You can use one of these:
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.appdata
In C# this translates in one of these statements:
static string[] Scopes = { DriveService.Scope.Drive };
// OR
static string[] Scopes = { DriveService.Scope.DriveAppdata };
// OR
static string[] Scopes = { DriveService.Scope.DriveFile };
Reference
Drive Files Create
I'm attempting to download a file from Google Drive using C# & Google.Apis.Drive.v3 and I'm getting an empty, zero-byte file (see code below). I'm uploading files OK, but can't get the download to work. Any help would be greatly appreciated.
code
static string[] Scopes = { DriveService.Scope.Drive };
static string ApplicationName = "Test001";
private DriveService _service = null;
public async Task downloadFile(string url, string lstrDownloadFile)
{
// Authorize API access
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Debug.WriteLine("Credential file saved to: " + credPath);
}
// Create Drive API service.
_service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Attempt download
// Iterate through file-list and find the relevant file
FilesResource.ListRequest listRequest = _service.Files.List();
listRequest.Fields = "nextPageToken, files(id, name, mimeType, originalFilename, size)";
Google.Apis.Drive.v3.Data.File lobjGoogleFile = null;
foreach (var item in listRequest.Execute().Files)
{
if (url.IndexOf(string.Format("id={0}", item.Id)) > -1)
{
Debug.WriteLine(string.Format("{0}: {1}", item.OriginalFilename, item.MimeType));
lobjGoogleFile = item;
break;
}
}
FilesResource.ExportRequest request = _service.Files.Export(lobjGoogleFile.Id, lobjGoogleFile.MimeType);
Debug.WriteLine(request.MimeType);
MemoryStream lobjMS = new MemoryStream();
await request.DownloadAsync(lobjMS);
// At this point the MemoryStream has a length of zero?
lobjMS.Position = 0;
var lobjFS = new System.IO.FileStream(lstrDownloadFile, System.IO.FileMode.Create, System.IO.FileAccess.Write);
await lobjMS.CopyToAsync(lobjFS);
}
It's possible that it's something as simple as not having enabled the Drive API on your project.
I recommend you add the following code. There's likely a download error which is preventing the stream from being filled.
FilesResource.ExportRequest request = ...
request.MediaDownloader.ProgressChanged += progress =>
{
switch (progress.Status)
{
case DownloadStatus.Failed:
{
Console.WriteLine("Failed: " + progress.Exception?.Message);
break;
}
// other status case statements if you need them
}
};
MemoryStream lobjMS = ...
Then you can drop a breakpoint into the Failed case or look at the exception in the console.
I'm writing a small desktop app that will upload file to google drive. So everything is fine when I'm sign in my google account, but when I'm not, program raises browser on this page "https://accounts.google.com/ServiceLogin". I'm using this code:
ClientSecrets secret = new ClientSecrets();
secret.ClientId = "my_client_id";
secret.ClientSecret = "my_client_secret";
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secret, new[] { DriveService.Scope.Drive }, "user", CancellationToken.None).Result;
var service = new DriveService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "TestUpload" });
File body = new File();
body.Title = "Title123";
body.Description = "Decription123";
body.MimeType = "image/png";
byte[] arr = System.IO.File.ReadAllBytes(fileName);
System.IO.MemoryStream stream = new System.IO.MemoryStream(arr);
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, "image/png");
request.Upload();
So how can I authorize programmatically with out raising the browser?
Most of your problem is the fact that you are not saving the Authentication. You are requesting access but not saving it. In the following example fileDataStore stores the authentication information in a file on your pc in %AppData% this way next time you run the program no authentication will be needed, and it also wont require that you are logged into Google at the time.
//Scopes for use with the Google Drive API
string[] scopes = new string[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile};
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential =
GoogleWebAuthorizationBroker
.AuthorizeAsync(new ClientSecrets { ClientId = CLIENT_ID
, ClientSecret = CLIENT_SECRET }
,scopes
,Environment.UserName
,CancellationToken.None
,new FileDataStore("Daimto.GoogleDrive.Auth.Store")
).Result;
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",
});
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 } };
// 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;
}
}
This code is ripped from the Google Drive C# upload tutorial, if you want more information on what its doing and how it works you may want to check that. There is also a working Sample project in the Google-Dotnet-Samples project on GitHub. The tutorial is based upon that sample project.