I am a beginner in C# so it will be helpful if you explain the issue in simple words. I have issue regarding uploading a video on my YouTube channel through server using YouTube API v3 but when I run my code locally I have no issues uploading a video.But hosting on IIS/Server gives object reference error.
Below is the code I am trying to execute for video uploading which is written on upload button.
protected async void btnUpload_Click(object sender, EventArgs e)
{
if (txtVideoTitle.Text != "" && txtFileUpload.HasFile)
{
date = DateTime.Now;
string CLIENT_ID = ConfigurationManager.AppSettings["ClientId"];
string CLIENT_SECRET = ConfigurationManager.AppSettings["ClientSecret"];
var youtubeService = AuthenticateOauth(CLIENT_ID, CLIENT_SECRET,"singleuser");
if (youtubeService == null) throw new ArgumentNullException("youtubeService");
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = txtVideoTitle.Text;
video.Snippet.Description = txtVideoDescription.Text;
video.Snippet.Tags = new string[] { "tag1", "tag2" };
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "unlisted";
if (video == null) throw new ArgumentNullException("video");
var filename = txtFileUpload.FileName;
Stream filepath = txtFileUpload.PostedFile.InputStream;
var videosInsertRequest = youtubeService.Videos.Insert(video,"snippet,status", filepath, "video/*");
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
message.Text = "Video Uploaded Successfully!!!";
}
else
{
message.Text = "Please enter required details...";
}
}
public static YouTubeService AuthenticateOauth(string cLIENT_ID, string cLIENT_SECRET, string v)
{
string[] scopes = new string[] { YouTubeService.Scope.Youtube,
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 = cLIENT_ID, ClientSecret = cLIENT_SECRET }
, scopes
, v
, CancellationToken.None
, new FileDataStore("Drive.Auth.Store")).Result;
YouTubeService service = new YouTubeService(new YouTubeService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Web"
});
if (service == null) throw new ArgumentNullException("service");
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
As you can see in the above code I have handled youtube service where it throws exception because it receives null value when I host it on server or IIS on company network.But when I run my code locally(development machine) It doesn't throw any exception.
I have spent days solving the issue but to no avail.Any help will be appreciated.
The exception message is
Server Error in '/' Application.
Value cannot be null.
Parameter name: youtubeService
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: youtubeService
Related
Currently i am trying to send message from C# to Google chat Room ,tried Authentication using following code
UserCredential credential;
var jsonPath = "";
jsonPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "client_secrets.json");
//using (var stream = new FileStream(jsonPath, FileMode.Open, FileAccess.Read))
using (var stream = new FileStream(jsonPath, FileMode.Open, FileAccess.Read))
{
string[] scopes = new[] { "https://www.googleapis.com/auth/chat"};
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
scopes,
"admin#XXXX.XX", CancellationToken.None, new FileDataStore("C:\\AlexaHangout\\Google.Hangout.Auth.Store")).Result;
}
// Create the service.
var service = new HangoutsChatService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "VSAHangout",
})
Message msg = new Message();
msg.Text = "Hi USER";
msg.Sender = new User() { DisplayName = "Test", Name = "admin#XXXXX.XX", ETag = "12345", Type = "BOT" };
msg.Space = new Space() { Name = "spaces/XXXXXXXX", DisplayName = "ViSev" }
SpacesResource.MessagesResource.CreateRequest req = new SpacesResource.MessagesResource(service).Create(msg, "spaces/XXXXXXX");
var result = req.Execute();
Authenication is working fine but when i trying to send message getting following error.
{"ClassName":"Google.GoogleApiException","Message":"Google.Apis.Requests.RequestError\r\nRequest had insufficient authentication scopes. [403]\r\nErrors [\r\n\tMessage[Request had insufficient authentication scopes.] Location[ - ] Reason[forbidden] Domain[global]\r\n]\r\n","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":" at Google.Apis.Requests.ClientServiceRequest`1.d__31.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Google.Apis.Requests.ClientServiceRequest`1.Execute()\r\n at HangoutSample.WebForm1.CheckService() in E:\\mahesh Works\\HangoutSample\\HangoutSample\\WebForm1.aspx.cs:line 70","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nMoveNext\nGoogle.Apis, Version=1.43.0.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab\nGoogle.Apis.Requests.ClientServiceRequest`1+d__31\nVoid MoveNext()","HResult":-2146233088,"Source":"Google.Apis","WatsonBuckets":null}
Judging by this maybe your scope should be set to:
string[] scopes = new[] { "https://www.googleapis.com/auth/chat.bot"};
Don't forget to delete the previously generated token.json with the old scope.
I am building a YouTube app for windows 8.1.
I am having a trouble with, add(Insert) subscription is fail
my code:
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
new Uri("ms-appx:///Assets/client_secrets.json"),
new[] { Uri.EscapeUriString(YouTubeService.Scope.Youtube) },
"user",
CancellationToken.None);
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
ApiKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
HttpClientInitializer = credential,
ApplicationName = "AppName"
});
Subscription body = new Subscription();
body.Snippet = new SubscriptionSnippet();
body.Snippet.ChannelId = "UC-kezFAw46x-9ctBUqVe86Q";
try
{
var addSubscriptionRequest = youtubeService.Subscriptions.Insert(body, "snippet");
var addSubscriptionResponse = await addSubscriptionRequest.ExecuteAsync();
}
catch (Exception e)
{
throw e;
}
When I set a breakpoint at the first line.
when execute to last line, breaks this function
Update(2015-11-14):
Error Message:
The subscription resource specified in the request must use the snippet.resorceId property to identify the channel that is being subscribed to [400]
Successful Code:
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
new Uri("ms-appx:///Assets/client_secrets.json"),
new[] { Uri.EscapeUriString(YouTubeService.Scope.Youtube) },
"user",
CancellationToken.None);
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
//ApiKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
HttpClientInitializer = credential,
ApplicationName = "4GameTV"
});
try
{
Subscription body = new Subscription();
body.Snippet = new SubscriptionSnippet();
body.Snippet.ResourceId = new ResourceId();
body.Snippet.ResourceId.ChannelId = "UC-kezFAw46x-9ctBUqVe86Q"; //replace with specified channel id
var addSubscriptionRequest = youtubeService.Subscriptions.Insert(body, "snippet");
var addSubscriptionResponse = await addSubscriptionRequest.ExecuteAsync();
}
catch (Exception e)
{
throw e;
}
Your authentication seems a bit off from what I normally use. Also ApiKey is only needed if you want to access public data.
string[] scopes = new string[] { YouTubeService.Scope.Youtube };
// 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
, "test"
, CancellationToken.None
, new FileDataStore("Daimto.YouTube.Auth.Store")).Result;
YouTubeService service = new YouTubeService(new YouTubeService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "YouTube Data API Sample",
});
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'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.
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.