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.
Related
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#
i am trying to upload documents using google Drive API integration, working fine in case of localhost but not working on live domain.
using (var stream = new FileStream(#"" + folderPathForCredentials, FileMode.Open, FileAccess.ReadWrite))
{
// 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 FolderPath = #"" + folderPathForToken;
String FilePath = Path.Combine(FolderPath, "token.json");
stream.Dispose();
stream.Close();
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = clientID,
ClientSecret = clientSecret
},
Scopes,
"user",
CancellationToken.None,
new FileDataStore(FilePath, true)).Result;
}
//create Drive API service.
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = applicationName,
});
return service;
And this is the code to Upload on Google Drive.
FilesResource.CreateMediaUpload request;
if (System.IO.File.Exists(path))
{
using (var stream = new System.IO.FileStream(path, System.IO.FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
request = _service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
request.Fields = "id";
request.Upload();
stream.Dispose();
stream.Close();
System.IO.File.Delete(path);
//return request.ResponseBody;
return Json(new JsonData { IsSuccess = true, Message = "Uploaded Successfully", Data = null });
}
}
Let me help in configuring the drive with live domain.
I am trying to upload a JSON file to the root folder in whoever's GDrive. I've search all through Google for an answer while trying to fix it myself. No matter what I've done request.Responsebody always returns null. Here I tried to do a blank .txt file (which still doesn't work).
This is the code to get the credentials and then it sets the resulting DeviceService to variable.
//GDrive Cred
public static void GetCred()
{
//Get Credential
UserCredential credential;
using (var stream =
new FileStream(Path + "\\client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = System.IO.Path.Combine(credPath, ".credentials/drive-dotnet-quickstart");
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,
});
mService = service;
}
and this is the code to upload the file.
//Save JSON to GDrive
public static void SaveJSONtoDrive()
{
GetCred();
// File's metadata.
Google.Apis.Drive.v2.Data.File body = new Google.Apis.Drive.v2.Data.File();
body.Title = "ATGEntries.txt";
body.Description = "Database JSON for Adventurer's Tour Guide";
//body.MimeType = "application/json";
body.MimeType = "text/plain";
body.Parents = new List<ParentReference>() { new ParentReference() { Id = "root" } };
// File's content.
byte[] byteArray = System.IO.File.ReadAllBytes(Path + "\\ATGEntries.txt");
MemoryStream stream = new MemoryStream(byteArray);
try
{
FilesResource.InsertMediaUpload request = mService.Files.Insert(body, stream, "text/plain");
request.UploadAsync();
Google.Apis.Drive.v2.Data.File file = request.ResponseBody;
// Uncomment the following line to print the File ID.
Console.WriteLine("File ID: " + file.Id);
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
}
Can someone please attempt to help me fix this strange error?
I cannot believe this isn't anywhere so I will answer my own question in the hopes that it will help someone else along the way.
Pay attention to the line where you set the 'credPath' variable
credPath = System.IO.Path.Combine(credPath, ".credentials/drive-dotnet-quickstart");
make sure the part after ".credentials/" needs to be the same name as whatever you named your OAuth 2.0 client ID in the Google Developers Console. This should fix the problem.
When I upload video to YouTube using client side login. The first time redirect to UI for permissions.
I want upload without redirect to web page. I need to execute this code on server.
Here is my code.
private async Task<string> Run(string title, string description, string filepath)
{
var videoID = string.Empty;
try
{
logger.Info(string.Format("[uploading file on youTube Title: {0}, Description: {1}, filePath: {2}]", title, description, filepath));
UserCredential credential;
using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
logger.Info("[Load credentials from google start]");
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
logger.Info("[Load credentials from google end]");
}
logger.Info("YouTubeApiKey {0}", System.Configuration.ConfigurationManager.AppSettings["YoutubeApiKey"]);
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApiKey = System.Configuration.ConfigurationManager.AppSettings["YoutubeApiKey"],
ApplicationName = System.Configuration.ConfigurationManager.AppSettings["ApplicationName"]
});
logger.Info("ApplicationName {0}", System.Configuration.ConfigurationManager.AppSettings["ApplicationName"]);
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = title;
video.Snippet.Description = description;
//video.Snippet.Tags = new string[] { "tag1", "tag2" };
// video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "public"; // or "private" or "public"
var filePath = filepath; // Replace with path to actual movie file.
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
}
return videoID;
}
catch (Exception e)
{
logger.ErrorException("[Error occurred in Run ]", e);
}
return videoID;
}
void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case UploadStatus.Uploading:
Console.WriteLine("{0} bytes sent.", progress.BytesSent);
break;
case UploadStatus.Failed:
Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
break;
}
}
void videosInsertRequest_ResponseReceived(Video video)
{
Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
}
Your code is doing is doing everything correctly. The YouTube API doesn't allow for pure server authentication (Service Account). The only option available to you to upload files will be to use Oauth2 and authenticate your code the first time.
I just sugest you make one small change add filedatastore. This will store the authentication for you. Once you have authenticated it via the web browser you wont need to do it again.
/// <summary>
/// Authenticate to Google Using Oauth2
/// Documentation https://developers.google.com/accounts/docs/OAuth2
/// </summary>
/// <param name="clientId">From Google Developer console https://console.developers.google.com</param>
/// <param name="clientSecret">From Google Developer console https://console.developers.google.com</param>
/// <param name="userName">A string used to identify a user.</param>
/// <returns></returns>
public static YouTubeService AuthenticateOauth(string clientId, string clientSecret, string userName)
{
string[] scopes = new string[] { YouTubeService.Scope.Youtube, // view and manage your YouTube account
YouTubeService.Scope.YoutubeForceSsl,
YouTubeService.Scope.Youtubepartner,
YouTubeService.Scope.YoutubepartnerChannelAudit,
YouTubeService.Scope.YoutubeReadonly,
YouTubeService.Scope.YoutubeUpload};
try
{
// 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 = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore("Daimto.YouTube.Auth.Store")).Result;
YouTubeService service = new YouTubeService(new YouTubeService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "YouTube Data API Sample",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
Call the above method like this:
// Authenticate Oauth2
String CLIENT_ID = "xxxxxx-d0vpdthl4ms0soutcrpe036ckqn7rfpn.apps.googleusercontent.com";
String CLIENT_SECRET = "NDmluNfTgUk6wgmy7cFo64RV";
var service = Authentication.AuthenticateOauth(CLIENT_ID, CLIENT_SECRET, "SingleUser");
Your code will need to be authenticated the first time. Once its authenticated filedatastore stores a file in %appData% on your machine. Every time it runs after that it will use the refresh token stored in %appData% to gain access again.
Code ripped from YouTube API Sample project
I am using the below code to integrate google drive with my C# example:
protected void Button1_Click(object sender, EventArgs e)
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "********************",
ClientSecret = "********************"
},
new[] { DriveService.Scope.DriveFile },
"user",
CancellationToken.None).Result;
// Create the service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",
});
File body = new File();
body.Title = "My document";
body.Description = "A test document";
body.MimeType = "image/jpeg";
string path = "";
byte[] byteArray = System.IO.File.ReadAllBytes("D:\\babita_backup\\Babita\\GoogledriveIntegration\\Koala.jpg");
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, "image/jpeg");
request.Upload();
File file = request.ResponseBody;
// Label1.Text = file.Id;
}
catch { }
}
And I have:
redirect uri as:
https://localhost:50027/GoogleAPI/callback.aspx
javascript origins as:
https://localhost:50027/
But every time when I try to login with the promt I am getting the error:
400 That’s an error.
Error: redirect_uri_mismatch
The redirect URI in the request: http://localhost:50804/authorize/ did not match a registered redirect URI.
Please note that here the port number changes automatically every time, no matter how many times I change it. Its not picking up the redirect uri that I mentioned in the app console.
you need to specify a fix port for the ASP.NET development server like How to fix a port number in asp.NET development server and add this url with the fix port to the allowed urls.