I'm wanting to copy an already existing Google Docs Spreadsheet to a new Google Docs spreadsheet. I dont think the v2.0 .NET API can handle it natively (or if so I can't find the class/method), however It looks like the v3.0 protocol can but I'm not sure how to implement this in the current framework or even if it is possible with the current .net api. eg. ~DocumentsFeed.copy() (pseudo code).
Exporting to a temp excel file then uploading with a new name is not possible either as some of the complex formulas get messed up in the conversion process.
I am a bit of a .NET noob so any info would be greatly appreciated eg. How would I go about doing this in .NET if I could only use the v3 protocol (ajax etc) and not the .NET API.
Thanks
EDIT: (final class thanks to #langsamu for his help!)
using System;
using Google.GData.Documents;
using Google.GData.Client;
using Google.GData.Extensions;
public class GoogleDocument
{
private DocumentsService ds;
private String username;
private String password;
public GoogleDocument(String username, String password)
{
this.ds = new DocumentsService("doc service name");
this.username = username;
this.password = password;
this.ds.setUserCredentials(username, password);
this.ds.QueryClientLoginToken();
}
public void copyDocument(String oldFileName, String newFileName)
{
SpreadsheetQuery query = new Google.GData.Documents.SpreadsheetQuery();
query.Title = oldFileName;
query.TitleExact = true;
DocumentsFeed feed = this.ds.Query(query);
AtomEntry entry = feed.Entries[0];
entry.Title.Text = newFileName;
var feedUri = new Uri(DocumentsListQuery.documentsBaseUri);
this.ds.Insert(feedUri, entry);
}
}
Google.GData.Documents.DocumentsService service = new Google.GData.Documents.DocumentsService("YOUR_APPLICATIONS_NAME");
service.setUserCredentials("YOUR_USERNAME", "YOUR_PASSWORD");
Google.GData.Documents.SpreadsheetQuery query = new Google.GData.Documents.SpreadsheetQuery();
query.Title = "YOUR_SPREADSHEETS_TITLE";
query.TitleExact = true;
Google.GData.Documents.DocumentsFeed feed = service.Query(query);
Google.GData.Client.AtomEntry entry = feed.Entries[0];
var feedUri = new Uri(Google.GData.Documents.DocumentsListQuery.documentsBaseUri);
service.Insert(feedUri, entry);
This solution is basically about retrieving an existing spreadsheet (service.Query) using the Document List API and re-inserting it (service.Insert).
Make sure you replace the ALL CAPS application name, username, password and spreadsheet title.
Add a reference to Google.GData.Documents.
This is using .NET 4 (should work with lower versions as well) and Google Documents List Data API v2.0 (DLL says version is 1.6.0.0: google-gdata), which seems to use version 3.0 of the protocol.
It is a bit unclear if you are developing a web application or a desktop application, so I'll try and cover both (essentially they are very much alike - because...).
If you are developing a web application you won't be able to make a 100% AJAX solution. You will only be able to request URL's on the same domain. To do this you will need to either do the communication server side only, or do it server side and proxy it to your web app through AJAX.
If you are developing a desktop application you'll have to do this stuff aswell. Except the AJAX part.
An example app would be fairly easy - 2-3 hours work to whip up considering the documentation given. With just a little knowledge of HTTP and POST request forming you should be able to make it work.
Related
I have been contemplating on a dilemma for hours. I have a Visual Studio Solution that contains a WCF, WebForms, UWP, Xamarin and a SharedLibrary Projects.
I intend to use the WCF project as the backend which talks to the database and process Email and SMS integration and feed the other apps.
OPTION A
Currently, The WCF is hosted on an Azure App Service which makes it accessible via POST, GET, etc from the url which is: https://mywcfprojectlink.azurewebsites.net/service1.svc/GetUsers
With such arrangements, I can perform a POST request to get data from the apps:
string response = string.Empty;
string url = "https://mywcfprojectlink.azurewebsites.net/service1.svc/GetUsers";
try
{
var values = new Dictionary<string, string>
{
{ "data", Encryption.EncryptString(dat.ToString()) } //dat is incoming method param
};
string jsonString = JsonConvert.SerializeObject(values);
var cli = new WebClient();
cli.Headers[HttpRequestHeader.ContentType] = "application/json";
response = cli.UploadString($"{url}", jsonString);
var result = JsonConvert.DeserializeObject<string>(response);
topic.InnerText = Encryption.DecryptString(result.ToString());
}
catch (Exception)
{
return string.Empty;
}
The method above is a simple one as I have other ones where I Deserialize with Models/Classes.
OPTION B
I equally have access to the methods defined in service1 by adding the project reference to my WebForms which surprisingly is also compatible with xamarin but not with UWP. Nevertheless, I am interested in the WebForms scenario. Below is an example method:
using BackEnd;
//Service1 service1 = new Service1();
//var send = service1.GetUsers(dat.ToString()); //dat is incoming method param
//topic.InnerText = send;
Obviously, using the Option B would eliminate the need to encrypt, decrypt, serialize or deserialize the data being sent. However, I have serious performance concerns.
I need to know the better option and if there is yet another alternative (probably an Azure Resource), you can share with me.
If you decide to use https endpoint of the Azure website, option A is secure because of SSL encryption. So you don't have to encrypt/decrypt it by yourself. The only tip is to create a proper authorization mechanism. For example use TransportWithMessageCredential. An example is provided in below article https://www.codeproject.com/Articles/1092557/WCF-Security-and-Authentication-in-Azure-WsHttpBin
I'm working on a UWP app and I was thinking about moving from the old LiveSDK (which is discontinued and was last updated around 2015) to the new OneDriveSDK (the Graph APIs), specifically using the UWP Community Toolkit Services package and its APIs.
The library seems pretty easy to use as far as login and files/folders management go, but so far I haven't been able to find a way to retrieve the user full name, the user email and the profile picture.
Here's the code I'm currently using to do so, using LiveSDK (code simplified here):
public static async Task<(String username, String email)> GetUserProfileNameAndEmailAsync(LiveConnectSession session)
{
LiveConnectClient connect = new LiveConnectClient(session);
LiveOperationResult operationResult = await connect.GetAsync("me");
IDictionary<String, object> results = operationResult.Result;
String username = results["name"] as String;
if (!(results["emails"] is IDictionary<string, object> emails)) return default;
String email = emails["preferred"] as String ?? emails["account"] as String;
return (username, email);
}
public static async Task<ImageSource> GetUserProfileImageAsync([NotNull] LiveConnectSession session)
{
LiveConnectClient liveClient = new LiveConnectClient(session);
LiveOperationResult operationResult = await liveClient.GetAsync("me/picture");
String url = operationResult.Result?["location"] as String;
// The URL points to the raw image data for the user profile picture, just download it
return default;
}
I've looked at the guide here and I see there seems to be a replacement for all of the above, but I haven't been able to integrate that with the UWP Toolkit service. For example, to retrieve the user info, here's what I've tried:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/");
await OneDriveService.Instance.Provider.AuthenticationProvider.AuthenticateRequestAsync(request);
using (HttpResponseMessage response = await OneDriveService.Instance.Provider.HttpProvider.SendAsync(request))
{
String content = await response.Content.ReadAsStringAsync();
}
But this fails with an exception at the SendAsync call.
NOTE: I know there are the Graph APIs too in the UWP Toolkit, with ready-to-use methods to retrieve the user info and profile picture, but apparently you need an office 365 subscription to use those APIs (both as a dev, and probably as a user too), so I guess that's not what I'm looking for here, since I've always been able to retrieve these info using a normal OneDrive client.
Is there a way to do this on UWP, either through some method within the UWP Toolkit, or with some other solution?
Thanks!
EDIT: I've reused the code from the sample app, registered my app to get a clientID and made a quick test, but it's not working as expected and I'm getting this exception:
Fixed, see below
EDIT #2: According to this question, I had to switch to https://graph.microsoft.com/beta to get the profile picture, as the 1.0 version of the APIs doesn't support it for normal MS accounts right now. All things considered, it seems to be working just fine now 👍
I followed the MSDN document to register my app for Microsoft Graph. After that, I will get an application ID(in API, it's called as clientId).
Then, I used the Microsoft Graph Connect Sample for UWP to login in with my general MS account. It worked well. I could get the username, email etc.
Please note that if you want to run this sample successfully, you would need to use the application ID to initialize the PublicClientApplication object in AuthenticationHelper.cs.
public static PublicClientApplication IdentityClientApp = new PublicClientApplication("your client id");
SCENARIO
I would like to develop a very simple app written in C# or Vb.Net using WinForms tech., that will help me to automate a simple task that consist in access to my Outlook.com account to read my emails received from Youtube then extract the video urls.
PROBLEM
My networking related knowledges are not good, I'm stuck at the most important point trying to find the easiest way to acchieve that task (I mean official Microsoft APIs for .Net or 3rd party APIs or other way to be able do this), trying to apply the required OAuth2 autorizathion to access the email account.
I know that the following code is not focused in the right direction because the lack of authorization, but I don't know how to implement that neither how to read the emails, so this is what I tried:
string url = "https://outlook.office.com/api/v2.0/me/messages";
string result = "";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
try {
using (WebClient wc = new WebClient()) {
wc.Encoding = Encoding.UTF8;
result = wc.DownloadString(url);
}
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
QUESTION
How I could access to my Outlook.com account to read the title and the content of the inbox emails that I have?. And, additionally but optionally to respond (only if possible and is not too much ask), how I could delete a email?.
Note that this question reffers to Outlook.com online service, not to Outlook's desktop client neither the usage of their COM libraries or Office365.
ANSWER REQUISITES
I know that I'm no one to ask for help and put some requisites, all kind of help is appreciated for me, but this time I need to put a special requisite, because my head got crazy trying to understand, use and adapt OAuth2 solutions that were made from scratch, it generates very long codes that I don't understand at all, it's too much for me.
For that reason, I will accept an answer in this question only if the provided solution is based in the usage of a 3rd pary library that will facilitate all this task because it will serve as a complete abstraction of the OAuth2 implementation, like RestSharp, CodeScales or DotNetOpenAuth, or whichever other (free)lib that will handle the required things for me instead of the need to develop the OAuth2 algorithms by myself from scratch.
RESEARCH
My investigation started reading this Microsoft's Outlook dev. page, following to this Mail API reference, this REST API documentation, this Outlook.com API, this kind of getting started article, and ending in this fully illustrative example using ASP.Net.
What I have taken in clear from the Microsoft articles is just... nothing of nothing, I've registered the app and created the client id and the secret, but Microsoft does not provide any example for Winforms so I tried to translate their official ASP.NET example to WinForms without success.
After that waste of time, I found this OAuth documentation page which provides some libraries for .NET that I imagine will facilitate the OAuth2 authorization, then I discovered the DotNetOpenAuth library which seems very complete, and also I found this code sample for Outlook using DotNetOpenAuth but again it is for ASP.NET, and also these generic and official DotNetOpenAuth's code samples but I can't find any thing that could help me for what I want to do.
The general idea is to follow the tutorial here: Get Started with Mail, Calendar, and Contacts REST APIs but I will try to simplify it and demonstrate it with a Winforms sample.
Register App
First things first, you need to create and register an application to the Application Registration Portal (you should only have to do this once for a given application of course):
create an app
generate a new password
add a platform, and choose mobile ("mobile" here means "any device", or "not for a browser"...)
don't forget to click on save!
Authentication
Now, in your "any device" code (including winforms), you'll need to authenticate. The simplest way is to use ADAL ("Active Directory Authentication Library"). The source is available here https://github.com/AzureAD/azure-activedirectory-library-for-dotnet and the binary is available as a nuget.
Unfortunately, the latest version which you can get on nuget today named Microsoft.IdentityModel.Clients.ActiveDirectory does not work for me (It had a bug I've reported here https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/412 that's already been fixed, but now the server complains about some app vs server incompatibility).
So you must use the old "Experimental" one (keep that in mind as someday in the future, we'll have to switch): Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory
You want to make sure you use the proper scopes when you do acquire an auth token. Scopes are defined here: Outlook mail, calendar, and contacts scopes and represent an area of permission. Without specifying scope, you can do nothing else but authenticate.
So, if you want to read mails, use the "https://outlook.office.com/mail.read" scope.
When you try the application, after the authentication dialog, it should display to the user the consent screen (here we see we asked for mail scope: "Read Your Mail"):
Office/Outlook/OData API
Once authentication works, you can use the REST api directly which is not that easy, or be lazy and use another package: Microsoft.Office365.OutlookServices-V2.0 that will do all underlying REST/OData magic for you. The good news is this API is quite complete so it should allow you to do other things like, message creation, delete, etc.
There is an important remark for the outlook.com case: not all accounts are enabled for this whole REST API (check the "REST API availability" chapter here: Outlook Mail), so you might want to create a new one for testing.
Here is the winforms code for a sample app that will query 10 messages and add them to a listbox.
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Office365.OutlookServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private const string authority = "https://login.microsoftonline.com/common";
private const string clientId = "blablabl-abla-blab-abla-blablablab"; // TODO: put your application id here
private const string redirectUri = "urn:ietf:wg:oauth:2.0:oob"; // put your redirect uri here (should be the same)
// we cache the token for the duration of this form
// you could/should use the FileCache class provided in the sample here https://dev.outlook.com/restapi/tutorial/dotnet
private TokenCache _cache = new TokenCache();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// since all packages force async,
// we have to avoid threading issues
BeginInvoke((Action)(() => GetMessages()));
}
private async void GetMessages()
{
// use the Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory nuget package for auth
var authContext = new AuthenticationContext(authority, _cache);
var result = await authContext.AcquireTokenAsync(
new[] { "https://outlook.office.com/mail.read" },
null,
clientId,
new Uri(redirectUri),
new PlatformParameters(PromptBehavior.Always, this));
// use the Microsoft.Office365.OutlookServices-V2.0 nuget package from now on
var client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0"), () => Task.FromResult(result.Token));
var messages = await client.Me.Messages
.Take(10) // get only 10 messages
.ExecuteAsync();
// fill some list box
// (beware, some messages have a null subject)
foreach (var msg in messages.CurrentPage)
{
listBox1.Items.Add(msg.Subject);
}
}
}
}
I just would like to share the (almost)final solution, I extended a little bit the solution provided by #Simon Mourier, to iterate all the emails of a specific folder and, if the email is from Youtube, scrap the urls inside, then recytle the email.
When to apply this?, well, just adapt it for any case on which you need to parse the emails, my case is very specific, I have around 500 channel subscriptions so I accumulate around 200 emais from Youtube in a month, most of the emails are from music channels that I just read the email to copy the url to download it with JDownloader, so this is usefull as a savetimer because it will do all the task for me.
Private Const Authority As String = "https://login.microsoftonline.com/common"
Private Const ClientId As String = "OUR API ID"
' Put your redirect uri here (should be the same).
Private Const RedirectUri As String = "urn:ietf:wg:oauth:2.0:oob"
' We cache the token for the duration of this Form.
' You could/should use the FileCache class provided in the sample here:
' https://dev.outlook.com/restapi/tutorial/dotnet
Private cache As New TokenCache()
Private Sub Form1_Shown() Handles MyBase.Shown
' Since all packages force async, we have to avoid threading issues.
Me.BeginInvoke(Sub() GetMessages())
End Sub
Private Async Sub GetMessages()
' Use the 'Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory' Nuget package for auth.
Dim authContext As New AuthenticationContext(Authority, cache)
Dim result As AuthenticationResult =
Await authContext.AcquireTokenAsync({"https://outlook.office.com/mail.readwrite"},
Nothing, ClientId, New Uri(RedirectUri),
New PlatformParameters(PromptBehavior.Auto, Me))
' Use the 'Microsoft.Office365.OutlookServices-V2.0' Nuget package from now on.
Dim client As New OutlookServicesClient(New Uri("https://outlook.office.com/api/v2.0"),
Function() Task.FromResult(result.Token))
' I have a rule set to automatically move all emails received from Youtube to a folder with name "Youtube".
Dim folder As IMailFolder =
Await client.[Me].MailFolders.Where(Function(f As IMailFolder) f.DisplayName = "Youtube").ExecuteSingleAsync()
Dim messages As IPagedCollection(Of IMessage) =
Await client.[Me].MailFolders.GetById(folder.Id).Messages.ExecuteAsync()
Do While True
Me.ParseYoutubeMessages(messages.CurrentPage)
If messages.MorePagesAvailable Then
messages = Await messages.GetNextPageAsync
Else
Exit Do
End If
Loop
End Sub
Private Async Sub ParseYoutubeMessages(ByVal messageList As IReadOnlyList(Of IMessage))
Dim urlRegex As New Regex("""http://www.youtube.com/.+watch.+uploademail""", RegexOptions.IgnoreCase)
For Each msg As IMessage In messageList
If (msg.From.EmailAddress.Name.Equals("YouTube", StringComparison.OrdinalIgnoreCase)) Then
Dim body As String = msg.Body.Content
Dim isMatch As Boolean = urlRegex.IsMatch(body)
If Not (isMatch) Then
Throw New InvalidOperationException("Youtube url regex doesn't match.")
Else
Dim urlMatches As MatchCollection = urlRegex.Matches(body)
Dim urls As String() =
(From m As Match In urlMatches.Cast(Of Match)
Select Environment.NewLine & m.Value).Distinct().ToArray()
File.AppendAllText("C:\Youtube Urls.txt", String.Join("", urls))
msg.IsRead = True
Await msg.MoveAsync("DeletedItems")
End If
End If
Next msg
End Sub
Updating this for 2018 -- Microsoft Graph API now has control over granting access to objects in the 365 world, including email. See this link for the 4-step overview: https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_user
The short question is whether is this possible and if so, how?
Outline
I have a .NET application which currently uses a service account to access information across a Google Apps domain using the Google Drive API. This works fine using the google-api-dotnet-client library and code along the same lines as shown in the samples here - which are currently a very good basic example of what I'm doing.
What I want to do now is extend it so as well as using those APIs provided by the "new" google-api-dotnet-client library, it uses the older "GData" libraries, as provided for via the
older google-gdata library, specifically the Spreadsheets API (and perhaps more to come).
The Problem
This is where the difficulty arises. The former library does exactly what I want, as evidenced by the second link in the first paragraph above - and the fact I have it doing it myself. HOWEVER... although the second library has been updated to support OAuth 2.0 in addition to OAuth 1.0 and the other older auth techniques, it does not - as far as I can tell from extensive Googling and trail-and-error - allow the "service account on behalf of all my users" operation which I need.
My question is whether I'm missing something (possibly a hard to find or undocumented something) which would allow me to do what I want. Failing that, is there any way I could force this behaviour and make these two libraries operate side by side?
The ideal solution
Ideally I would love some way of having the Google.GData.Spreadsheets.SpreadsheetsService instance be able to take advantage of the Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient> instance I'm already using... somehow. Is such witchcraft possible? I'm I missing the obvious?
Failing that, I'm happy to do the whole OAuth2 "assertion flow client" dance again if I have to, in some way that the older library can handle.
Help?
Other Thoughts
I have considered - and rejected for the time being - the option of starting from scratch and writing my own library to make this happen. This is for two reasons:
The gdata library already exists, and has been developed by many people likely cleverer than myself. I'm not so arrogant that I believe I can do better.
I'm not certain the OAuth2 with service account approach is even supported/allowed on these older APIs.
An alternate approach which I've been hoping to avoid but may have to fall back to depending on the answers here will be to use 2-legged OAuth 1.0 for portions of this. I'd prefer not to, as having parts of the app rely on one old auth method whilst other parts do it the nice new way just feels wrong to me. And there's that much more to go wrong...
Updates
I have considered the possibility of subclassing GDataRequestFactory and GDataRequest so I can make my own request factory and have that take the instance of Google.Apis.Authentication.Auth2Authenticator<AssertionFlowClient> (well, an instance of Google.Apis.Authentication.IAuthenticator anyway) which could step in to authenticate the request just before it's called. However... the constructor for GDataRequest is internal, which has stopped me.
It's really looking like this isn't meant to be.
For the sake of other folks coming across this question (now that the solution linked to in the accepted answer uses deprecated code), here's how I solved it:
First, start in "new API" land (use the Google.Apis.Auth nuget package) by setting up a ServiceAccountCredential following Google's Service Account example:
//In the old api, this accessed the main api accounts' sheets, not anymore
//** Important ** share spreadsheets with the Service Account by inviting the "serviceAccountEmail" address to the sheet
string serviceAccountEmail = "12345697-abcdefghijklmnop#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"key.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { "https://spreadsheets.google.com/feeds", "https://docs.google.com/feeds" }
}.FromCertificate(certificate));
Tell the credential to request an Access Token:
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait();
Now it's time to switch back to "old API" land (use the Google.GData.Spreadsheets nuget package). Start by constructing the SpreadsheetsService (similar to Google's example):
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
To use Service Account authentication, we'll create an instance of the GDataRequestFactory and set a custom Authorization header:
var requestFactory = new GDataRequestFactory("My App User Agent");
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
Finally, set the SpreadsheetsService's RequestFactory property to this new factory:
service.RequestFactory = requestFactory;
And go ahead and use the SpreadsheetsService as you would had you authenticated using any other technique. (Tip: share spreadsheets with the Service Account by inviting the serviceAccountEmail address to the sheet)
I managed to solve this by subclassing GDataRequestFactory and creating my own implementation of the interfaces implemented by GDataRequest. This implementation wraps an instance of GDataRequest instantiated via reflection, and adds in the necessary code to perform authentication using an instance of IAuthenticator (in my case, Auth2Authenticator).
I wrote a blog post on it and added an example as a Gist:
Blog: Using Google's Spreadsheet API using .NET, OAuth 2.0 and a Service Account
Gist 4244834
Feel free to use this if it helps you (BSD licence).
Hey just stumbled accross the same problem and produced a different solution:
Has anybody ever concidered of writing the parameters from the credentials-object directly to an OAuth2Parameters-Object?
I did this and it worked nicely:
public class OAuthTest
{
OAuth2Parameters param = new OAuth2Parameters();
public OAuthTest()
{
Debug.WriteLine("Calling: AuthGoogleDataInterface()");
bool init = AuthGoogleDataInterface();
if (init)
{
GOAuth2RequestFactory requestFactory = new GOAuth2RequestFactory(null, "My App User Agent", this.param);
//requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
var service = new SpreadsheetsService("MyService");
service.RequestFactory = requestFactory;
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.Query(query);
// Iterate through all of the spreadsheets returned
foreach (SpreadsheetEntry entry in feed.Entries)
{
// Print the title of this spreadsheet to the screen
Debug.WriteLine(entry.Title.Text);
}
}
Debug.WriteLine(m_Init);
}
private bool AuthGoogleDataInterface()
{
bool b_success;
try
{
Console.WriteLine("New User Credential");
// New User Credential
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
GoogleClientSecrets GCSecrets = GoogleClientSecrets.Load(stream);
string[] ArrScope = new[] { "https://spreadsheets.google.com/feeds", "https://docs.google.com/feeds" };
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GCSecrets.Secrets,
ArrScope,
"user", CancellationToken.None,
new FileDataStore("My.cal")).Result;
// put the Information generated for the credentials object into the OAuth2Parameters-Object to access the Spreadsheets
this.param.ClientId = GCSecrets.Secrets.ClientId; //CLIENT_ID;
this.param.ClientSecret = GCSecrets.Secrets.ClientSecret; //CLIENT_SECRET;
this.param.RedirectUri = "urn:ietf:wg:oauth:2.0:oob"; //REDIRECT_URI;
this.param.Scope = ArrScope.ToString();
this.param.AccessToken = credential.Token.AccessToken;
this.param.RefreshToken = credential.Token.RefreshToken;
}
Debug.WriteLine("AuthGoogleDataInterface: Success");
b_success = true;
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
b_success = false;
}
return b_success;
}
}
I need to get the free Google charts working over SSL without any security errors. I am using c# and asp.net.
As Google charts does not support SSL by default, I am looking for a robust method of using there charts but ensuring my user doesn't get any security warnings over their browser.
One thought was to use a handler to call the charts api and then generate the output my site needs.
Similar to Pants are optional blog post. I haven't been able to get this example working at this stage.
Any suggestions, or samples are welcome.
Thanks
the Google Charts API is now available over HTTPS at via https at chart.googleapis.com.
Source: http://www.imperialviolet.org/2010/11/29/charthttps.html
We do this automatically in the NetQuarry Platform - it's pretty simple, although you do force the image to come through your site vs. charts.google.com, making your browser run the request through a single connection.
Since a chart is just a link to an image, what we do is to build the link to the chart (a much more complex process, obviously), then add the whole link to the query string on an internal handler (handler.ashx?req=chart& ). So the new link looks like this:
handler.ashx?act=chrt&req=chart&cht=p3&chs=450x170&chd=s:HAR9GBA&chl=New|In%20Progress|Responded|Won't%20Respond|On%20Hold|Future|Review|&chg=20,20,1,5&chg=10,25,1,5&chco=0A477D
Then, we simply download the image data and write it back as the response.
Here's the code:
Blockquote
private void GoogleChart(HttpContext cxt)
{
const string csPrefix = "?act=chrt&req=chart&";
HttpRequest req = cxt.Request;
HttpResponse rsp = cxt.Response;
string sUrl = cxt.Request.RawUrl;
int nStart = sUrl.IndexOf(csPrefix, StringComparison.OrdinalIgnoreCase);
rsp.Clear();
if (nStart > 0)
{
sUrl = "http://chart.apis.google.com/chart?" + sUrl.Substring(nStart + csPrefix.Length);
System.Net.WebClient wc = new System.Net.WebClient();
byte[] buffer = wc.DownloadData(sUrl);
cxt.Response.ClearContent();
cxt.Response.ClearHeaders();
cxt.Response.ContentType = "application/octet-stream";
cxt.Response.AppendHeader("content-length", buffer.Length.ToString());
cxt.Response.BinaryWrite(buffer);
}
}
I Have a partial solution that has one issue.
here is the link to my new post asking for help with a specific problem regarding my solution
My Attempt at a SSL handler