Trying to build a Twitter Thread programmatically - c#

I've built a Twitter application that works in C#. It's a WPF or Windows-like application that makes a web request to the Twitter API endpoint. Now, I have a business case to create a Twitter thread when it's sending a series of 280-character tweets. Because of all the business rules we have, there's no way I can use an existing Twitter app on the market.
The issue is that I'm always getting a 401 unauthorized whenever I try to send a tweet with the in_reply_to_status_id_str. In fact it does this whenever I try to add ANY OPTIONAL PARAMETERS besides the required STATUS parameter. I'm using OAuth 1.0A.
I'm trying to create a series of Tweets that will display Show This Thread at the bottom and can be viewed together.
The method I've provided would be called in a loop for each 280-character segment.
NOTE: I NOW HAVE THIS WORKING. I REALIZED YOU HAVE TO ORDER THE PARAMETERS BEFORE SIGNING THEM
public async Task<string> TwitterWebRequest(string status, string resource_url, string authHeader, int counter)
{
string id = "";
using (var request = new HttpRequestMessage(HttpMethod.Post, resource_url))
{
request.Headers.TryAddWithoutValidation("Authorization", authHeader);
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var data = new Dictionary<string, string>();
if (counter == 0)
{
data = new Dictionary<string, string>
{
["status"] = status
};
}
else
{
data = new Dictionary<string, string>
{
["in_reply_to_status_id"] = "1169662308278292480",
["status"] = status
};
}
request.Content = new FormUrlEncodedContent(data);
using (HttpResponseMessage response = await client.Value.SendAsync(request))
{
JavaScriptSerializer json = new JavaScriptSerializer();
string responseStream = await response.Content.ReadAsStringAsync();
Dictionary<string, object> jsonObj = json.DeserializeObject(responseStream) as Dictionary<string, object>;
if (counter == 0) { id = jsonObj["id_str"].ToString(); }
if (response.StatusCode == HttpStatusCode.OK) {
return "OK";
}
else { return ""; }
}
}
This is what I'm doing so far for the signature:

This is what I did to make it work. I had to put the parameters in order. This is a requirement for OAuth, otherwise you'll get a 401 Unauthorized.
private static string CreateBaseString(string oauth_nonce, string oauth_timestamp, string status)
{
string baseFormat = "in_reply_to_status_id=1169662308278292480&oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}"
+ "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&status={6}";
string baseString = String.Format(baseFormat, oauth.OAuth_Consumer_Key, oauth_nonce, oauth.OAuth_Signature_Method,
oauth_timestamp, oauth.OAuth_Token, oauth.OAuth_Version, EncodingUtils.UrlEncode(status));
return String.Concat("POST&", EncodingUtils.UrlEncode(oauth.Resource_Url), "&", EncodingUtils.UrlEncode(baseString));
}

Related

Jira Rest API login error in JIRA SERVER using C#

I want connect to jira server using C# Rest api
https://jira.myserver.co.kr/rest/auth/1/session
enter code here
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.ContentType = "application/json";
request.Method = method;
... more
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
the remote server returned an error (404)
I tried different work arounds but all went in vain. May I know why this error is coming? What could be the resolution of this error?
You can search for a reason of this error in different ways:
by looking at logs of JIRA server, there might be some messages/stacktraces there (for example, atlasian-jira.log);
by using some tool to perform/debug/test REST calls (for example, postman), and when it's start working in tool you can write code to do it programmatically. JIRA can return description of error in the response, and tool can show it to you.
When you get this information it can give you exact reason why it is not working. Once I got 403 error and it was because threshold of unsuccessful login attempts was exceeded, I logged into JIRA server using web browser (and entered captcha), and after that I was able to obtain session through application code.
I can successfully obtain session from JIRA in the following way using postman:
Request type: POST
URL: https://myjiraserver.com/rest/auth/1/session
Body: {"username":"myusername","password":"mypassword"}
Headers: Content-Type:application/json
you can do something like this:
namespace YOUR_NAME_SPACE
{
public class jira
{
public static string createTicket(string url, string data)
{
try
{
var client = new System.Net.Http.HttpClient();
string base64Credentials = GetEncodedCredentials();
var header = new AuthenticationHeaderValue("Basic", base64Credentials);
client.DefaultRequestHeaders.Authorization = header;
var content = new StringContent(data, Encoding.UTF8, "application/json");
var result = client.PostAsync(url, content).Result;
var response = result.Content.ReadAsStringAsync().Result;
// You can call putIssue if you want
return response;
}
catch (System.Net.WebException ex)
{
Console.WriteLine("Exception Occurred" + " : {0}", ex.Message);
throw;
}
}
private static string GetEncodedCredentials()
{
string mergedCredentials = string.Format("{0}:{1}", "LOGIN", "PASSWD");
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
return Convert.ToBase64String(byteCredentials);
}
public static string jiraSerialise(string project, string summary, string description, string issutype, string author)
{
JObject valuesToJson =
new JObject(
new JProperty("fields",
new JObject(
new JProperty("project",
new JObject(new JProperty("key", project))),
new JProperty("summary", summary),
new JProperty("description", description),
new JProperty("issuetype",
new JObject(new JProperty("name", issutype))),
new JProperty("assignee",
new JObject(new JProperty("name", author))))));
return valuesToJson.ToString();
}
public static string putSerialize(string key, string value)
{
JObject valueToJson =
new JObject(
new JProperty(key, value));
return valueToJson.ToString();
}
public static string putIssue(string response, string author, System.Net.Http.HttpClient client)
{
JObject jsonResponse = JObject.Parse(response);
Dictionary<string, string> dictResponse = jsonResponse.ToObject<Dictionary<string, string>>();
string issueUrl = dictResponse.Last().Value;
string issueAssignee = issueUrl + "/assignee";
var authorContent = new StringContent(author, Encoding.UTF8, "application/json");
var authorResult = client.PutAsync(issueAssignee, authorContent).Result;
var authorResponse = authorResult.Content.ReadAsStringAsync().Result;
Console.WriteLine(authorResponse);
return authorResponse;
}
}
}
And now you can call this class like that:
string data = jira.jiraSerialise("lala", "nameVulnerabilty", "descriptionField", "Bug", "author");
string url = "http://YOUR_URL/rest/api/2/issue/";
Console.WriteLine(jira.createTicket(url, data));
Hope it helps :)

PowerBI and Azure AD Headless Login

I am trying to embed PowerBI dashboards into my customer MVC portal. My customers don't have AAD accounts, so they can't login to Live when they come to the website, they log into my MVC website with individual authority.
I have registered my App on PowerBI/AAD and have the ClientID and Secret. I make the call to AAD and get an Authorization Code which I then use to get an Athentication Token which the is returned successfully.
When ever I use the access token to get a dashboard it is continually rejected with a 403 Forbidden.
I have gone through all the samples from Microsoft, but they require a user login prompt. I have reviewed the ADAL2.0 code which refers to the AcquireToken Method, but this was deprecated in ADAL3 and replaced with AcquireTokenAsync which has different parameters and I am using this in my example below.
Here is the function to get the token:
protected AuthenticationResult GetAccessToken()
{
string pBiUser = Properties.Settings.Default.PowerBIUser;
string pBiPwd = Properties.Settings.Default.PowerBIPwd;
string pBiClientId = Properties.Settings.Default.PowerBIClientId;
string pBiSecret = Properties.Settings.Default.PowerBIClientSecret;
TokenCache TC = new TokenCache();
ClientCredential CC = new ClientCredential(pBiClientId,pBiSecret);
string AU = Properties.Settings.Default.PowerBIAuthority;
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext authenticationContext
= new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(AU, TC);
AuthenticationResult result = authenticationContext.AcquireTokenAsync("https://analysis.windows.net/powerbi/api"
,CC).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the PowerBI token");
}
return result;
}
I then take the result token and call. The response receives the 403:
protected PBIDashboards GetDashboards(AuthenticationResult authResult)
{
PBIDashboards pbiDashboards = new PBIDashboards();
var baseAddress = new Uri("https://api.powerbi.com");
using (var httpClient = new System.Net.Http.HttpClient {BaseAddress = baseAddress})
{
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("authorization",
"Bearer " + authResult.AccessToken);
using (**var response** = httpClient.GetAsync("v1.0/myorg/dashboards").Result)
{
string responseData = response.Content.ReadAsStringAsync().Result;
//Deserialize JSON string
pbiDashboards = JsonConvert.DeserializeObject<PBIDashboards>(responseData);
if (pbiDashboards != null)
{
var gridViewDashboards = pbiDashboards.value.Select(dashboard => new
{
Id = dashboard.id,
DisplayName = dashboard.displayName,
EmbedUrl = dashboard.embedUrl
});
}
}
}
return pbiDashboards;
}
Based on the error message(403), the issue is relative to the permission.
And AFAIK the is no such permission we can use when we acquire the access token using the client credentials flow for the Power BI REST. You can refer the permission for the figure below:
To get the token for the Power BI REST without user interaction, we can use the Resource owner password credentials flow. And you can use the 3rd party library PowerBI.Api.Client which already implement this.
After a lot of research, you can make a direct AJAX call to get the token:
private async Task<string> GetAccessToken()
{
string pBiUser = Properties.Settings.Default.PowerBIUser;
string pBiPwd = Properties.Settings.Default.PowerBIPwd;
string pBiClientId = Properties.Settings.Default.PowerBIClientId;
string pBiSecret = Properties.Settings.Default.PowerBIClientSecret;
string pBITenant = Properties.Settings.Default.PowerBITenantId;
string tokenEndpointUri = "https://login.microsoftonline.com/"+pBITenant+"/oauth2/token";
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", pBiUser),
new KeyValuePair<string, string>("password", pBiPwd),
new KeyValuePair<string, string>("client_id", pBiClientId),
new KeyValuePair<string, string>("client_secret", pBiSecret),
new KeyValuePair<string, string>("resource", "https://analysis.windows.net/powerbi/api")
});
using (var client = new HttpClient())
{
HttpResponseMessage res = client.PostAsync(tokenEndpointUri, content).Result;
string json = await res.Content.ReadAsStringAsync();
AzureAdTokenResponse tokenRes = JsonConvert.DeserializeObject<AzureAdTokenResponse>(json);
return tokenRes.AccessToken;
}
}
Once you have the string AccessToken, you can then call the Dashboards request.
protected PBIDashboards GetDashboards(string token)
{
PBIDashboards pbiDashboards = new PBIDashboards();
var baseAddress = new Uri("https://api.powerbi.com");
using (var httpClient = new System.Net.Http.HttpClient {BaseAddress = baseAddress})
{
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("authorization",
"Bearer " + token);
using (var response = httpClient.GetAsync("v1.0/myorg/dashboards").Result)
{
string responseData = response.Content.ReadAsStringAsync().Result;
//Deserialize JSON string
pbiDashboards = JsonConvert.DeserializeObject<PBIDashboards>(responseData);
if (pbiDashboards != null)
{
var gridViewDashboards = pbiDashboards.value.Select(dashboard => new
{
Id = dashboard.id,
DisplayName = dashboard.displayName,
EmbedUrl = dashboard.embedUrl
});
}
}
}
return pbiDashboards;
}
This will provide you the list of dashboards and the dashboard Id to call the PowerBI API to build the embeded page in Javascript. I used hidden input fields to store the access token and embed URL to pass over to the Javascript call.
// check if the embed url was selected
var embedUrl = document.getElementById('embed').value;
if (embedUrl === "")
return;
// get the access token.
accessToken = document.getElementById('token').value;
// Embed configuration used to describe the what and how to embed.
// This object is used when calling powerbi.embed.
// You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
var config = {
type: 'dashboard',
accessToken: accessToken,
embedUrl: embedUrl
};
// Grab the reference to the div HTML element that will host the dashboard.
var dashboardContainer = document.getElementById('dashboard');
// Embed the dashboard and display it within the div container.
var dashboard = powerbi.embed(dashboardContainer, config);

HttpClient: The uri string is too long

Given the following attempt to post data to a web service that generates PDF files, PDF rocket (which is awesome by the way).
I get the error Invalid URI: The uri string is too long
Why would anyone impose an arbitrary limit on POSTed data?
using (var client = new HttpClient())
{
// Build the conversion options
var options = new Dictionary<string, string>
{
{ "value", html },
{ "apikey", ConfigurationManager.AppSettings["pdf:key"] },
{ "MarginLeft", "10" },
{ "MarginRight", "10" }
};
// THIS LINE RAISES THE EXCEPTION
var content = new FormUrlEncodedContent(options);
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
I receive this rediculous error.
{System.UriFormatException: Invalid URI: The Uri string is too long.
at System.UriHelper.EscapeString
at System.Uri.EscapeDataString
at System.Net.Http.FormUrlEncodedContent.Encode
at System.Net.Http.FormUrlEncodedContent.GetContentByteArray
This reminds me of 640k ought to be enough... I mean really?
If, like me, you're faced with some wonky 3rd party web service that will only accept form content, you can work around the problem like this:
// Let's assume you've got your key-value pairs organised into a nice Dictionary<string, string> called formData
var encodedItems = formData.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. You could send it as JSON in the http message instead of the URI which is the recommended way to send larger chunks of data in an HttpPost/HttpPut. I altered your code to make use of it. This assumes that your service you are contacting can work with JSON (.net Web Api out of the box should have no problem with this).
using (var client = new HttpClient())
{
// Build the conversion options
var options = new
{
value = html,
apikey = ConfigurationManager.AppSettings["pdf:key"],
MarginLeft = "10",
MarginRight = "10"
};
// Serialize our concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(options);
var content = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
Make sure to install newtonsoft json.
I just solved a similar problem. For me I was integrating with a backend I didn't control and had to POST file along with form data (eg customerID) as form variables. So switching to JSON or Multipart would break the backend I didn't control. The problem was that large files would cause the FormUrlEncodedContent to throw an error saying "The uri string is too long".
This is the code that solved it for me after two days of effort (note still needs to be tweaked to be ASYNC).
private string UploadFile(string filename, int CustomerID, byte[] ImageData) {
string Base64String = "data:image/jpeg;base64," + Convert.ToBase64String(ImageData, 0, ImageData.Length);
var baseAddress = new Uri("[PUT URL HERE]");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
try {
//ENCODE THE FORM VARIABLES DIRECTLY INTO A STRING rather than using a FormUrlEncodedContent type which has a limit on its size.
string FormStuff = string.Format("name={0}&file={1}&id={2}", filename, HttpUtility.UrlEncode(Base64String), CustomerID.ToString());
//THEN USE THIS STRING TO CREATE A NEW STRINGCONTENT WHICH TAKES A PARAMETER WHICH WILL FormURLEncode IT AND DOES NOT SEEM TO THROW THE SIZE ERROR
StringContent content = new StringContent(FormStuff, Encoding.UTF8, "application/x-www-form-urlencoded");
//UPLOAD
string url = string.Format("/ajax/customer_image_upload.php");
response = client.PostAsync(url, content).Result;
return response.Content.ToString();
}
catch (Exception ex) {
return ex.ToString();
}
}
}
#Mick Byrne :
Thanks - your solution worked like a charme!
Here is my complete code:
public async Task DateienSendenAsync (string PfadUndDatei, string Dateiname, String VRPinGUID, String ProjektGUID, String VRPinX, String VRPinY, String VRPinZ)
{
var client = new HttpClient();
// Create the HttpContent for the form to be posted.
var requestContent = new[] {
new KeyValuePair<string, string>("dateiname", Dateiname),
new KeyValuePair<string, string>("bild", Convert.ToBase64String(File.ReadAllBytes(PfadUndDatei))),
new KeyValuePair<string, string>("VRPinGUID", VRPinGUID),
new KeyValuePair<string, string>("ProjektGUID", ProjektGUID),
new KeyValuePair<string, string>("ebene", "ebene"),
new KeyValuePair<string, string>("raumnummer", "raumnummer"),
new KeyValuePair<string, string>("ansichtsname", "ansichtsname"),
new KeyValuePair<string, string>("VRPinX", VRPinX),
new KeyValuePair<string, string>("VRPinY", VRPinY),
new KeyValuePair<string, string>("VRPinZ", VRPinZ),
};
String url = "http://yourhomepage/path/upload.php";
var encodedItems = requestContent.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
}

Fetch Facebook user profile details with profile picture and Logout properties using Facebook C# SDK

i want to fetch user details with profile picture using Facebook c# SDK.I have done some coding and able to login using Facebook in my app.I am explaining my code below.
immediateHelp.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Request.Params["code"] != null)
{
//Facebook.FacebookAPI api = new Facebook.FacebookAPI();
FacebookClient client = new Facebook.FacebookClient(GetAccessToken());
object me = client.Get("/me");
lblTextImage.ImageUrl="need picture here" ;
lblTextEmail.Text="need email here";
// JSONObject meFriends = client.Get("/me/friends");
}
}
}
private string GetAccessToken()
{
if (HttpRuntime.Cache["access_token"] == null)
{
Dictionary<string, string> args = GetOauthTokens(Request.Params["code"]);
HttpRuntime.Cache.Insert("access_token", args["access_token"], null, DateTime.Now.AddMinutes(Convert.ToDouble(args["expires"])), TimeSpan.Zero);
}
return HttpRuntime.Cache["access_token"].ToString();
}
private Dictionary<string, string> GetOauthTokens(string code)
{
Dictionary<string, string> tokens = new Dictionary<string, string>();
string clientId = "*************";
string redirectUrl = "http://localhost:3440/immediateHelp.aspx";
string clientSecret = "************************";
string scope = "user_photos,email";
string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}&scope={4}",
clientId, redirectUrl, clientSecret, code, scope);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string retVal = reader.ReadToEnd();
foreach (string token in retVal.Split('&'))
{
tokens.Add(token.Substring(0, token.IndexOf("=")),
token.Substring(token.IndexOf("=") + 1, token.Length - token.IndexOf("=") - 1));
}
}
return tokens;
}
I need to attach image in image field and email in text Box after login.I need also logout properties with destroy session using Facebook c# SDK.Please help me to resolve this.
The following code will help you get email and profile picture. The code client.Get("/me?fields=picture")) return picture in format of Json so that we need to extract the url as the code show :
FacebookClient client = new FacebookClient(access_token);
dynamic myInfo = fb.Get("/me?fields=email");
var picture = (((JsonObject)(JsonObject)client.Get("/me?fields=picture"))["picture"]);
var url = (string)(((JsonObject)(((JsonObject)picture)["data"]))["url"]);
lblTextImage.ImageUrl=url;
lblTextEmail.Text=myInfo.email;
Hop this work for you.

Youtube v3 api 401 Unauthorized

I am trying to upload a file using v3 of the youtube api and without using the c# library. I really can't use the library because I am making my own library that allows me to use a few common apis (youtube, vimeo, facebook, etc)
I have already got my access token and refresh token which is fine. Now I need to upload a file using the youtube resumable uploads defined here:
https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
but for some reason my code is coming back with a 401 Unauthorized error but I can't see why.
Here is my code that is creating the request:
private void CreateUploadRequest(SynchronisedAsset asset)
{
var endPoint = api.ApiUrl + "/videos?uploadType=resumable&part=snippet&key=" + api.Tokens.ConsumerKey; // read for the different ways to interact with videos https://developers.google.com/youtube/v3/docs/#Videos
var maxSize = 68719476736; // 64 gig
try
{
var location = CompanyProvider.GetUploadLocation(this.baseUploadDirectory, companyId, FileType.Asset);
var filePath = System.IO.Path.Combine(location, asset.FileName);
using (var data = new FileStream(filePath, FileMode.Open))
{
if (maxSize > data.Length && (asset.MimeType.ToLower().StartsWith("video/") || asset.MimeType.ToLower().Equals("application/octet-stream")))
{
var json = "{ \"snippet\": { \"title\": \"" + asset.FileName + "\", \"description\": \"This is a description of my video\" } }";
var buffer = Encoding.ASCII.GetBytes(json);
var request = WebRequest.Create(endPoint);
request.Headers[HttpRequestHeader.Authorization] = string.Format("Bearer {0}", api.Tokens.AccessToken);
request.Headers["X-Upload-Content-Length"] = data.Length.ToString();
request.Headers["X-Upload-Content-Type"] = asset.MimeType;
request.ContentType = "application/json; charset=UTF-8";
request.ContentLength = buffer.Length;
request.Method = "POST";
using (var stream = request.GetRequestStream())
{
stream.Write(buffer, 0, (int)buffer.Length);
}
var response = request.GetResponse();
}
}
}
catch (Exception ex)
{
eventLog.WriteEntry("Error uploading to youtube.\nEndpoint: " + endPoint + "\n" + ex.ToString(), EventLogEntryType.Error);
}
}
api.ApiUrl is https://www.googleapis.com/youtube/v3. I am not sure if the key is needed, it doesn't show it in the documentation but I added it to see if I could solve my Unauthorized issue.
Also, I figured that without the key, how would it know what account to upload to?
Can anyone see what is wrong with my code?
Any help would be greatly appreciated.
Update 1
After a bit of time sorting stuff out, I have now added some code that checks the youtube credentials before trying to do an upload. This is done with these bits of code:
public string GetAuthorizeApplicationUrl()
{
var sb = new StringBuilder();
var dictionary = new Dictionary<string, string>
{
{"client_id", Tokens.ConsumerKey},
{"redirect_uri", callbackUrl},
{"response_type", "code"},
{"scope", "https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtubepartner"},
{"approval_prompt", "force"},
{"access_type", "offline"},
{"state", ""}
};
sb.Append(requestTokenUrl);
foreach (var parameter in dictionary)
{
var query = (sb.ToString().Contains("?")) ? "&" : "?";
sb.Append(query + parameter.Key + "=" + parameter.Value);
}
return sb.ToString();
}
This bit of code is responsible for building the URL that allows us to ask the user for access.
With the code that is returned to our return URL we call this bit of code:
public void RequestAccessToken(string code)
{
var dictionary = new Dictionary<string, string>
{
{"code", code},
{"client_id", Tokens.ConsumerKey},
{"client_secret", Tokens.ConsumerSecret},
{"redirect_uri", callbackUrl},
{"grant_type", "authorization_code"}
};
var parameters = NormalizeParameters(dictionary);
var resultString = "";
using (var wc = new WebClient())
{
//wc.Headers[HttpRequestHeader.Host] = "POST";
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
resultString = wc.UploadString(requestAccessTokenUrl, parameters);
}
var json = JObject.Parse(resultString);
Tokens.AccessToken = json["access_token"].ToString();
Tokens.RefreshToken = (json["refresh_token"] != null) ? json["refresh_token"].ToString() : null;
Tokens.Save(companyId);
}
Now because we have declared our app as offline, when we do any api calls we can just use this bit of code:
public bool CheckAccessToken()
{
try
{
RefreshToken(); // Get and store our new tokens
return true;
}
catch
{
return false;
}
}
private void RefreshToken()
{
var dictionary = new Dictionary<string, string>
{
{"refresh_token", Tokens.RefreshToken},
{"client_id", Tokens.ConsumerKey},
{"client_secret", Tokens.ConsumerSecret},
{"grant_type", "refresh_token"}
};
var parameters = NormalizeParameters(dictionary);
var resultString = "";
using (var wc = new WebClient())
{
//wc.Headers[HttpRequestHeader.Host] = "POST";
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
resultString = wc.UploadString(requestAccessTokenUrl, parameters);
}
var json = JObject.Parse(resultString);
Tokens.AccessToken = json["access_token"].ToString();
Tokens.Save(companyId);
}
In my windows service I have this code:
public void SynchroniseAssets(IEnumerable<SynchronisedAsset> assets)
{
if (api.CheckAccessToken())
{
foreach (var asset in assets)
{
var uploadAssetThread = new Thread(() => CreateUploadRequest(asset));
uploadAssetThread.Start(); // Upload our assets at the same time
}
}
}
which as you can see calls the Original code above.
The error which I am getting when I parse it into json is this:
{
"error":{
"errors":[
{
"domain":"youtube.header",
"reason":"youtubeSignupRequired",
"message":"Unauthorized",
"locationType":"header",
"location":"Authorization"
}
],
"code":401,
"message":"Unauthorized"
}
}
So, if anyone could help me work out what that means, that would be great.
Cheers,
/r3plica
The reason "youtubeSignupRequired" usually means the YouTube account has not been set up properly or you have not created your YouTube channel yet. This is a requirement before you can upload videos.
It would be great if Google could improve their error message for this case and make it a bit more verbose.
The issue returning 401 Unautorized was because the account I was gaining access to did not have a youtube account associated with it.

Categories

Resources