How can I send a tweet from an unattended C# application? So far, I've tried TweetSharp, but that isn't working for me (no errors, but no success either). Here's the background info...
I have set up two twitter accounts to test this (lets call them TwitterSender and TwitterReceiver). TwitterReceiver is "following" TwitterSender. I went to dev.twitter.com and logged in as TwitterSender and clicked the "Create New App" button. From here, I was able to find things called "API Key", "API Secret", "Consumer Key", "Consumer Secret", "Access Token", and "Access Token Secret". When I'm logged in as TwitterSender I can see that I have granted read/write/direct message access. How can I tie all this together so that I can simply run the C# console application and have it send a tweet ("Hello World!") from TwitterSender so that any followers (e.g. TwitterReceiver) will get it? I'm OK with hard-coding user/password in plain-text. In the code below, I get no errors at all, but ultimately TwitterStatus ends up being null, and there is no indication that a tweet was sent either from the perspective of TwitterSender or TwitterReceiver.
TwitterClientInfo twitterClientInfo = new TwitterClientInfo();
twitterClientInfo.ConsumerKey = ConsumerKey; //Read ConsumerKey out of the app.config
twitterClientInfo.ConsumerSecret = ConsumerSecret; //Read the ConsumerSecret out the app.config
TwitterService twitterService = new TwitterService(twitterClientInfo);
twitterService.AuthenticateWith(AccessToken, AccessTokenSecret);
Console.WriteLine("Enter a Tweet");
string tweetMessage;
tweetMessage = Console.ReadLine();
TwitterStatus twitterStatus = twitterService.SendTweet(tweetMessage);
I got this working finally! In short, to send a tweet from, say, a Windows form without requiring a user to log in, you would do the following:
go to dev.twitter.com, log in as the account you want to send tweets from, and then create an "Application". A twitter "Application" in this sense is really just an authorization mechanism and not something that a user interacts with at all.
You will be asked for a website during the process of creating the application...After watching a Turkish video tutorial on how this was done, I entered http://www.google.com/tr, but it's likely that Uzbekistan ("uz" I believe) would work equally well). No, I have no idea why you need this.
Leave "Callback URL" blank and uncheck "Allow this application to sign in with Twitter".
Set the permissions of your application to read/write
Generate your OAuth keys - there should be four keys: the "API Key" (AKA Consumer Key), "API Secret" (AKA ConsumerSecret), "Token Key", and "Token Secret".
Now, go to twitter.com and log into your account (different than dev.twitter.com). Under "Settings" (hidden under the gear icon I think), there should be an "Apps" tab where you should see the application that you just created. You may need to grant it permissions from here (or it may already be set). You can also revoke permissions here.
Using Visual Studio 2012 and .NET framework 4.5 (NOT VS2010), get TweetSharp from NuGet. This project is no longer maintained or supported by the original developer, so don't expect much documentation or guidance if things don't work.
Write your code. For example, in a button click event...
var service = new TweetSharp.TwitterService("ConsumerKey","ConsumerSecret","TokenKey","TokenSecretKey"); //Replace keys with values from step #5
var twitterStatus = service.SendTweet(new SendTweetOptions() { Status ="Hello World" });
if (twitterStatus != null)
{
MessageBox.Show("It worked");
}
Note - You can't send the exact same tweet more than once per ___ (some undocumented amount of time). When there is an authentication problem, twitterStatus will return null - if that happens, check your keys, perhaps repermission and regenerate them again.
Related
Is there a way to change the default user id (which is 'default-user') in bot emulator?
Or maybe it supports something about multi conversations in the same time?
I want to emulate two different users at the same time (because I have multiple user types in my project.
When I try to create new conversation like this
....
var connector = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
var userAccount = new ChannelAccount("//here we need to provide user id which is always default-user", "Provider");
var botAccount = context.Activity.Recipient;
var conversation = await connector.Conversations.CreateDirectConversationAsync(botAccount, userAccount);
var message = context.MakeMessage();
message.Recipient = userAccount;
message.From = botAccount;
message.Conversation = new ConversationAccount(false, conversation.Id);
await connector.Conversations.SendToConversationAsync((Activity) message);
My emulator opens new conversation in the same chat-window
Bot Framework Channel Emulator had the functions you need in the previous versions. In the latest one AFAIK changing user id and group conversation simulation are not available out of the box. However the good thing is that what this tool is doing - it is just sending http requests to your WebApi endpoint. It means that you can catch those requests using Fiddler or any other similar tool and then edit and reissue the request. It is a workaround, but for testing pusposes I think it is okay to use such an approach.
Below is the Fiddler screen and screen of debug session to show it is working:
If you want to go further and automate it - there is a REST Api documentation on botframework site, so you can build your own client.
I work on the Bot Framework Emulator. We've recently added the ability to override generated user ids to be used in conversations without the need of a tool like Fiddler. You can utilize this feature in our latest release. I hope you find this useful for your scenario.
I don't know a way of having multiple conversations with different users, but you cant change the id/name of the user that is currently sending messages.
You can do this by editing the config file that the emulator uses to store its settings.
On linux I found this settings file here:
~/.config/botframework-emulator/botframework-emulator/server.json
You'll find a section "users" in that json file.
Change that section to:
"users": {
"currentUserId": "default-user2",
"usersById": {
"default-user": {
"id": "default-user",
"name": "User"
},
"default-user2": {
"id": "default-user2",
"name": "User2"
}
}
You'll need to restart the emulator and then your conversation should be with User2 now instead of User.
When you want to change it back you just need to change:
"currentUserId": "default-user2",
back to
"currentUserId": "default-user",
On windows follow these steps:
go to directory
%APPDATA%\botframework-emulator\botframework-emulator
locate server.json file
In the sections of users replace default-user
with id you need (in my case romel)
"users": {
"currentUserId": "default-user",
"usersById": {
"default-user": {
"id": "romel",
"name": "User"
}
}
}
restart bot emulator
Basically what I'm trying to do is to get recent tweets from a user and do stuff with them. I'm using Tweetinvi with PIN-based authentication, as described on the website, like this:
// Create a new set of credentials for the application
var appCredentials = new TwitterCredentials("CONSUMER_KEY", "CONSUMER_SECRET");
// Go to the URL so that Twitter authenticates the user and gives him a PIN code
var url = CredentialsCreator.GetAuthorizationURL(appCredentials);
// This line is an example, on how to make the user go on the URL
Process.Start(url);
// Ask the user to enter the pin code given by Twitter
var pinCode = Console.ReadLine();
// With this pin code it is now possible to get the credentials back from Twitter
var userCredentials = CredentialsCreator.GetCredentialsFromVerifierCode(pinCode, appCredentials);
// Use the user credentials in your application
Auth.SetCredentials(userCredentials);
Now the problem is that I have to sign in and connect to Twitter every time I launch my application via browser, which is mildly annoying. I've tried to save my authentication details in a text file (Consumer Key, Consumer Secret, Access Token, Access Token Secret), and then just insert the info into appCredentials and userCredentials, but with no results, as I keep getting TwitterNullCredentialsException. So how do I save my credentials so that I don't have to reconnect on every launch?
I am the main developer of Tweetinvi.
If you store the 4 credentials information you can then reuse them with 2 different solutions :
Auth.SetUserCredentials("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET");
// OR
var creds = new TwitterCredentials("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET");
Auth.SetCredentials(creds);
The documentation might help you set up your application : https://github.com/linvi/tweetinvi/wiki/Introduction
I need some help with examples how to use Credential of a current user running application.
So in windows 7 you can run application using user loged in by simply running application or you can use "Run as a different User" option and run it as another user.
In my Active Directory I have 2 account Domain User and one with Domain Admin rights. I'm login Windows as a Domain User and when I need I'm using "Run as a different User" to launch some task as a Domain Admin.
So the task is to get my Credential and use it to perform some task, lets say rename active directory user name.
Best way to do this as I can see is to ask user running application to enter Domain Admin credential on then start application and use them for various task. Of course I can easily run application with "Run as a different User" but I still need to get this credential and use them.
I've searched through the web and I can't find this, all i could find is using credential for a web auth.
If you can show me some examples how to:
1) Ask user for a Admin user credential ( i can leave without this )
2) Get and use credentials of a user running application
I don't want to know password I know I can't. Don't really want to add to a WPF form password box I prefer to use windows API to handle this i've already entered user name and password using "Run as a different User".
PS: I sorry if this topic exists :( I guess I'm bad at creating correct search requests.
ADDED: to be more clear what I need. In powershell it will look like this:
# This Asks user to enter credentials
$cred = Get-Credential;
# this checks if I have rights to use them.
Get-ADDomain “DOMAIN” –Server “Domain.com” –Credential $cred;
Of course it's simplified as hell though the point is that I can use credentials user entered when ever it's needed.
The equivalent C# to your Get-ADDomain is quite simple, it is just
public void PerformSomeActionAsAdmin(string adminUsername, string adminPassword)
{
//Null causes the constructor to connect to the current domain the machine is on.
// |
// V
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, null, adminUsername, adminPassword))
{
//do something here with ctx, the operations will be performed as whoever's username and password you passed in.
}
}
if you don't want to connect to the current domain and instead want to connect to Domain.com then replace the null with the appropriate string.
EDIT: if you want to use secure strings you can't use System.DirectoryServices.AccountManagement.PrincipalContext, you will need to go with the lower level calls in System.DirectoryServices.Protocols. Doing this process is quite complex, here is a link to the MSDN article "Introduction to System.DirectoryServices.Protocols (S.DS.P)" explaining how to use it. It is a big complex read and honestly I don't think it is worth it to be able to use encrypted strings.
public void PerformSomeActionAsAdmin(NetworkCredential adminCredential)
{
using(LdapConnection connection = new LdapConnection("fabrikam.com", adminCredential))
{
// MAGIC
}
}
Do you want to check if the current user is a doman admin? start by looking at his code, it should help you get started identifying what AD groups the current user is in. This will give you a list of strings that are each group's name the current user belongs to. Then you can check that list against whatever AD group you are trying to check for. Replace YourDomain with your domain name:
WindowsIdentity wi = WindowIdentity.GetCurrent();
List<string> result = new List<string>();
foreach (IdentityReference group in wi.Groups)
{
result.Add(group.Translate(typeof(NTAccount)).ToString().Replace("YourDomain\\", String.Empty));
}
Since i'm not quite sure what you're trying to do, this also might be helpful. You'd have to get the user name and password from a textobx, password box etc. This could be used for an "override" to use, for example, a manager's credentials etc. to do something the current user wasn't allowed to do because of AD group membership etc.
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YourDomain"))
{
if (UserName.Contains("YourDomain\\"))
{
UserName = UserName.Replace("YourDomain\\", String.Empty);
}
//validate the credentials
bool IsValid = pc.ValidateCredentials(UserName, Password);
}
I have some JavaScript that logs in a Facebook user and saves the access token to a database:
window.fbAsyncInit = function () {
FB.init({
appId: '<%=FaceBookApplicationId() %>',
status: false, // check login status
cookie: true,
oauth: true
});
};
function facebookLogin() {
FB.login(function(response) {
if (response.authResponse) {
__doPostBack('__Page', 'FacebookDeliveryButton: ' + JSON.stringify(response.authResponse));
} else {
console.log('User cancelled login or did not fully authorize.');
}
}, { scope: 'offline_access,read_stream,publish_stream,user_photos' });
}
A button click fires facebookLogin() which logs in a facebook user, getting a facebook session that includes an access token, which I JSON serialize and post to the server. The server then saves this access token to the database table FacebookDeliveryQueue.
I have a Windows service running that periodically queries the FacebookDeliveryQueue table and attempts to post on a user's wall using the access token we saved earlier:
IQueryable<FacebookDeliveryQueue> toSend = objectContext.FacebookDeliveryQueues.Where(p => !p.IsDelivered);
foreach (FacebookDeliveryQueue facebookDeliveryQueueItem in toSend)
{
string facebookAccessToken = facebookDeliveryQueueItem.Cart.FacebookAccessToken;
string facebookRecipientId = facebookDeliveryQueueItem.Cart.FacebookRecipientId;
var client = new FacebookClient(facebookAccessToken);
dynamic parameters = new ExpandoObject();
parameters.message = facebookDeliveryQueueItem.Cart.CustomMessageBody;
client.Post(facebookRecipientId + "/feed", parameters);
}
My problem is, this ONLY works with access tokens from the user that created the facebook application. E.g.
Success:
I, the creator of this application, log in and pick one of my friends to send a message to, this info is saved to the database, the service runs, my message is posted to my friend's wall.
Failure:
I log in on my dummy test account (approving the app permissions on this account), pick one of my dummy test account's friend, this info is saved to the database, the service runs and throws an invalid access token error.
Any ideas why?
Update: Switched to Oauth login -- no change. Still getting "(OAuthException) Invalid access token signature." when attempting to post to friend's wall.
Looks like you're using facebook's old login methods, which they recently just turned off, so your old access tokens aren't valid anymore? And your javascript isn't generating the right kind of token. Read the latest version of the FB.login documentation for more info on what changes you need to make. Specifically,
pass oauth: true to the FB.init call
check for response.authResponse instead of response.session now.
Also, check that your app isn't in "sandbox mode". Go to the app settings page and click on "advanced". Sandbox mode makes it so that only developers can use the app.
The persistence to the database was silently trimming the access token to 75 characters, which in the case of my own user, was enough (small user id because it's an old account) -- but five characters too short in the case of my test account which has a very large user id.
Woops.
i am in a middle of developing a facebook asp.net c# application
now the application store the access_token of the users in a database and i olso write my expire time, and facebook id.
for example when a user pass authentication i store in the db a record for the user with his access_token, and expire=DateTime.UtcNow+5 minutes, and his facebook id
now the application run a background Thread every 1 minute.
the Thread checks every user if is expire < DateTime.UtcNow and if so-> it post on it wall
i know that the facebook access_token expire in somting like 1 hour
now my problem is that sometimes it's post and sometimes not,
it's not steady.
and i make the post in a loop and i use PostAsync.
the code:
for (int i = 0; i < records.Count; i++)
{
//init the facebookClient with valid access_token
Facebook.FacebookClient fbc = new Facebook.FacebookClient(records[i].token_data);
Dictionary<string, object> post = new Dictionary<string, object>();
post.Add("message", "my message");
post.Add("link", "http://mylink/");
post.Add("picture", "http://somepic.gif");
post.Add("name", "my app name");
post.Add("caption", "text text text");
post.Add("description", "text text text");
post.Add("actions", "{\"name\":\"Play Now!\", \"link\":\"http://my app page/\"}");
//the punchline
fbc.PostAsync(records[i].facebook_id.ToString() + "/feed", post);
}
now it cold run 50-100 loops
with my tests for some users i'ts post and for some not
and not all time.
If I understand you correctly, you are sending the same message every time to the user's wall? Your problem may be Facebook. If there is no variation in your message, Facebook tends to ignore the second message (or it may just simply add the phrase "X similar posts").
What you are trying to do sounds very "spammy" from a Facebook perspective (they are very harsh on doing this type of things). If you are writing a message to a user's wall, you really should be asking the user if it's OK to do so (no you don't have to, but it should be done in conjunction with the user's activity on your app.. like posting a game score). If users report that you are spamming their wall, your app will be pulled by Facebook, so you might want to rethink what you are trying to do.
(I doubt this is the answer you wanted to hear, and as a result I doubt you will mark me as an answer, but if your research verifies what I have told you, it would be nice to get marked as the answer.. or at least voted up by another reader).