I am attempting to write a C# wrapper for the Twilio Programmable Chat tool. The library provided is for JS clients. I thought that using a tool like ClearScript (V8) would allow me to wrap the js as needed.
The example code on the site is
const Chat = require('twilio-chat');
// Make a secure request to your backend to retrieve an access token.
// Use an authentication mechanism to prevent token exposure to 3rd parties.
const accessToken = '<your accessToken>';
Chat.Client.create(accessToken)
.then(client => {
// Use Programmable Chat client
});
so after I initialize
using (var engine = new V8ScriptEngine())
{
engine.Execute(#"
const Chat = require('twilio-chat.js');
const token = 'my token';
Chat.Client.create(token).then(client=>{
});
");
}
The program errors on the 'require' line with the error require is not defined.
I have read that require is simply returning the module exports so I replaced the require('...
with
engine.Execute(#"
const Chat = ('twilio-chat.js').module.exports;
...
but that errors with Cannot read property 'exports' of undefined'
I got the js file from https://media.twiliocdn.com/sdk/js/chat/releases/4.0.0/twilio-chat.js
How can I get around this or maybe there is a better way. I appreciate any and all insights.
Thanks
I don't know anything about Twilio, but here's how to enable ClearScript's CommonJS module support. This sample loads the script from the web, but you can limit it to the local file system or provide a custom loader:
engine.AddHostType(typeof(Console));
engine.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableWebLoading;
engine.DocumentSettings.SearchPath = "https://media.twiliocdn.com/sdk/js/chat/releases/4.0.0/";
engine.Execute(new DocumentInfo() { Category = ModuleCategory.CommonJS }, #"
const Chat = require('twilio-chat');
const token = 'my token';
Chat.Client.create(token).then(
client => Console.WriteLine(client.toString()),
error => Console.WriteLine(error.toString())
);
");
This successfully loads the Twilio script, which appears to be dependent on other scripts and resources that aren't part of the bare standard JavaScript environment that ClearScript/V8 provides. To get it working, you'll have to augment the search path and possibly expose additional resources manually. As shown, this code prints out ReferenceError: setTimeout is not defined.
Related
First, I'm a total noob with AWS Lambda so I wanted to see if anyone can point me in the right direction to setting up an AWS Lambda function that will send a Twilio MMS message that would be triggered by an upload of an image to an S3 bucket? I guess C# isn't a hard set requirement but it would be nice since that is the language that I'm currently working with.
I'm currently doing this via my app but want to offload this to an AWS Lambda function if at all possible.
TIA
I'm neither a C# expert nor very familiar with AWS Lamda, but this post here should get you started.
And this documentation page explains how to send messages with C#. So the only thing you need to do is add the Twilio Account SID and Auth key to the Lamda environment variables, and there you go.
// Install the C# / .NET helper library from twilio.com/docs/csharp/install
using System;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
class Program
{
static void Main(string[] args)
{
// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
body: "Join Earth's mightiest heroes. Like Kevin Bacon.",
from: new Twilio.Types.PhoneNumber("+15017122661"),
to: new Twilio.Types.PhoneNumber("+15558675310")
);
Console.WriteLine(message.Sid);
}
}
Now a days i am implementing sentiment analysis through google cloud library,my code is
string text = "Feeling Not Well";
var client = LanguageServiceClient.Create();
var response = client.AnalyzeSentiment(new Document()
{
Content = text,
Type = Document.Types.Type.PlainText
});
var sentiment = response.DocumentSentiment;
var Score = sentiment.Score;
var magnitude = sentiment.Magnitude;
but it gives an error on
var client = LanguageServiceClient.Create();.
the error is
The Application Default Credentials are not available.
They are available if running in Google Compute Engine.
Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS
must be defined pointing to a file defining the credentials.
See https://developers.google.com/accounts/docs/application-default-credentials for more information.
please give me solution
You can either use
gcloud auth application-default login
from the command line (assuming you have the Cloud SDK installed), or generate and download a service account JSON file and then set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point to that file.
The Create method call will first check the environment variable, and then look for application default credentials from gcloud if the environment variable isn't set.
Basically, the credential options are:
Explicitly create one from a service account file, e.g. GoogleCredential.FromStream(stream) and use that to create a Channel which you can pass into Create, as described in the FAQ
Call create without any arguments (or passing in null) in which case:
If you've set the GOOGLE_APPLICATION_CREDENTIALS environment variable, it is assumed that's where the service account JSON file is
Otherwise, if you've run gcloud auth application-default login those credentials will be used
Otherwise, if you're running on Google Cloud Platform (e.g. Compute Engine or AppEngine Flexible) you will get the default credentials for the project
Otherwise, the call will fail
Additionally, you can use the Document.FromPlainText call to simplify your code:
string text = "Feeling Not Well";
var client = LanguageServiceClient.Create();
var response = client.AnalyzeSentiment(Document.FromPlainText(text));
var sentiment = response.DocumentSentiment;
var Score = sentiment.Score;
var magnitude = sentiment.Magnitude;
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
I have set up a basic C# application to run a PageSpeed test on a website that I specify using the Google.Apis.Pagespeedonline.v2 nuget package.
The set up is simple enough and I have a variable that I can specify the url which is then past in to the Service
// Create the service.
var service = new PagespeedonlineService(new BaseClientService.Initializer
{
ApplicationName = "PageSpeed Sample",
ApiKey = "[API_KEY_HERE]"
});
var url = "URL_TO_TEST";
// Run the request.
var result = await service.Pagespeedapi.Runpagespeed(url).ExecuteAsync();
The problem being the .Runpagespeed method ONLY accepts URL. I need to be able to specify, at minimum, the 'Mobile' strategy so I can obtain scores for both Desktop and Mobile. I know this is possible in other libraries but seems to be missing in .NET. Is anybody aware of a way to do this using the .NET library? In the reference documentation it implies that the method accepts further optional parameters but it does not in the code.
Pagespeedapi: runpagespeed has an optional value called strategy
strategy string The analysis strategy to use
Acceptable values are: "desktop": Fetch and analyze the URL for
desktop browsers "mobile": Fetch and analyze the URL for mobile
devices
Example:
var request = service.Pagespeedapi.Runpagespeed(url);
request.Strategy = Google.Apis.Pagespeedonline.v2.PagespeedapiResource.RunpagespeedRequest.StrategyEnum.Mobile;
var results = request.Execute();
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;
}
}