Looking for desktop Oauth example.

Sep 6, 2010 at 12:12 AM

I am trying to rework the Linq2Twitter example to work on a desktop.  From the program.cs, I am looking for a good way to obtain the ConsumerKey, ConsumerSecret and the Pin.  I see in the demo, the app is returning Console.Readline but im confused on returning it to where?  I would like to have seperate config form, and I believe i should pass to the form the object that handles all of this.  Without all of the docs on Linq2Twitter, im lost on what is really going on...  would I pass the var oauth? 

im also confused on the oauth.GetVerifier = () => line... im fairly new to Linq.  i understand LinqtoXML but lambda expressions I am not.  I have asked a few questions here and have seen others ask, but I never see any answers.  Is there a better place for support?  Joe, help us lol.

 

private static void InitializeOAuthConsumerStrings(TwitterContext twitterCtx)
        {
            var oauth = (DesktopOAuthAuthorization)twitterCtx.AuthorizedClient;
            oauth.GetVerifier = () =>
            {
                Console.WriteLine("Next, you'll need to tell Twitter to authorize access.\nThis program will not have access to your credentials, which is the benefit of OAuth.\nOnce you log into Twitter and give this program permission,\n come back to this console.");
                Console.Write("Please enter the PIN that Twitter gives you after authorizing this client: ");
                return Console.ReadLine();
            };



            if (oauth.CachedCredentialsAvailable)
            {
                Console.WriteLine("Skipping OAuth authorization step because that has already been done.");
            }
        }
Coordinator
Sep 11, 2010 at 9:23 PM

Hi,

There's actually two points of extensibility that you can find in Program.cs.  First, there's an if statement, checking the config files for your tokens. 
If the tokens aren't in your config file, then it creates a UsernamePasswordAuthorization. However, since basic authentication was deprecated at the
end of August, this isn't going to work.  Therefore, you'll need to use the code in the else case, for DesktopOAuthAuthorization, shown here:

                auth = new DesktopOAuthAuthorization();
                // If you wanted to pass the consumer key and secret in programmatically, you could do so as shown here.
                // Otherwise this information is pulled out of your .config file.
                ////var desktopAuth = (DesktopOAuthAuthorization)auth;
                ////desktopAuth.ConsumerKey = "some key";
                ////desktopAuth.ConsumerSecret = "some secret";
Notice the commented out part.  This is where you can pop up a window, ask for the tokens (key and secret), extract the 
tokens from the window text boxes, and set ConsumerKey and ConsumerSecret. This was the first part. Next is managing the PIN.
Since you're running a desktop application, Twitter can't perform the normal OAuth protocol flow that it does with Web 
apps; specifically, redirecting back to your application. Therefore, they have this PIN submission step to associate the
intial token authorization request with the API call. This part of the process is initiated through the integration of OAuth
with LINQ to Twitter. Here's what kicks this part off:
            using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/"))
            {
...

                // If we're using OAuth, we need to configure it with the ConsumerKey etc. fou rom the user.
                if (twitterCtx.AuthorizedClient is OAuthAuthorization)
                {
                    InitializeOAuthConsumerStrings(twitterCtx);
                }

As you can see, the InitializeOAuthConsumerStrings executes if we've initialized TwitterContext with an OAuthAuthorization object,
which was set up in the previous step. Here's the pertenent part of the method you need to know:
 
            oauth.GetVerifier = () =>
            {
                Console.WriteLine("Next, you'll need to tell Twitter to authorize access.\nThis program will not have access to your credentials, which is the benefit of OAuth.\nOnce you log into Twitter and give this program permission,\n come back to this console.");
                Console.Write("Please enter the PIN that Twitter gives you after authorizing this client: ");
                return Console.ReadLine();
            };

Instead of the Console operations, you'll want to pop up a window with a text box. After the user enters the PIN into the
text box and clicks an OK button, you grab the pin in this code, and return that value. GetVerifier is a lambda of type Func<string>,
which means it's just an unnamed method that returns a string. It gets executed by the OAuth provider in LINQ to Twitter.
You can see the point where this happens if you return to the call to InitializeOAuthConsumerStrings, where a few lines later, the
code calls auth.SignOn.
What's cool is that you'll be able to see this whole protocol in action if you fire up Fiddler (or your favorite HTTP traffic viewer), 
turn off encryption, step through the code with the debugger, and watch the messages go by.
I would have written a sample, but don't have the bandwidth right now. Hopefully, this will point you in the right direction.
Joe
 
Sep 13, 2010 at 5:20 PM

Joe thank you very much.  Prior to your reply, I have gotten real close.  It seems though, in testing, it will not always send me to the PIN page on Twitter.  I think it is because the app is already authorized.  I reset the key and secret, thinking that would prompt me for a pin.  Here is what I have so far...  can you or anyone tell me if I am close or can suggest a mod?

It does pop up my dialog page if I do not have a key/secret.  when I enter those, it saves them in the configuration file.  I would like to make sure I have logic that takes me to the next step.  If I hit the OK button at that point I believe it opens up the dialog one more time, sends me to the pin page, and I can enter the pin and save it...

I am not so sure it will work a second time..as like I said, I believe the app is now authorized.    I am willing to send the project to someone to look at and or use for their testing.

 what my app does is, once authorized, will read the tweets of the user and put them in a list box.  to the right of that list box, is another list box.  the app will let you pick and choose tweets on the left, and add them to the box on the right.

these now are "approved tweets"  and it will email the approved tweets (to me at this time...ill make it where you can configure the email address later).

I do not show the code for that section of the app, just the form startup and the configuration form

 snipits from my main form:

public bool IsConfigured
        {
            get
            {
                return !String.IsNullOrEmpty(Settings1.Default.consumerKey) &&
                    !String.IsNullOrEmpty(Settings1.Default.consumerSecret);
                    
            }
        }
        private void InitializeOAuthConsumerStrings(TwitterContext twitterCtx)
        {
           
            var oauth = (DesktopOAuthAuthorization)twitterCtx.AuthorizedClient;

            

            
                oauth.GetVerifier = () =>
                {
                    //Console.WriteLine("Next, you'll need to tell Twitter to authorize access.\nThis program will not have access to your credentials, which is the benefit of OAuth.\nOnce you log into Twitter and give this program permission,\n come back to this console.");
                    //Console.Write("Please enter the PIN that Twitter gives you after authorizing this client: ");
                    //return Console.ReadLine();

                       if (string.IsNullOrEmpty(Settings1.Default.pin))
                       {
                           ConfigureForm dlgSettings = new ConfigureForm();
                           dlgSettings.ShowDialog();
                       }
                       
                    return Settings1.Default.pin;
                };

if (oauth.CachedCredentialsAvailable)
            {
                Console.WriteLine("Skipping OAuth authorization step because that has already been done.");
                
            }
        }
        private void Form1_Shown(object sender, EventArgs e)
        {

            
            Console.WriteLine("loading key from form shown: " + Settings1.Default.consumerKey);
            Console.WriteLine("loading secret from form shown: " + Settings1.Default.consumerSecret);
            Console.WriteLine("loading pin from form shown: " + Settings1.Default.pin);
            ConfigureForm dlgSettings = new ConfigureForm();

            if (string.IsNullOrEmpty(Settings1.Default.consumerKey) || string.IsNullOrEmpty(Settings1.Default.consumerSecret))
            {
                Console.WriteLine("Skipping OAuth authorization demo because twitterConsumerKey and/or twitterConsumerSecret are not set in your .config file.");
                Console.WriteLine("Loading Config Page instead");

                // For username/password authorization demo...
                //auth = new UsernamePasswordAuthorization(Utilities.GetConsoleHWnd());
                //UsernamePasswordAuthorization up = new UsernamePasswordAuthorization();
                
               // auth = new UsernamePasswordAuthorization(this);
               // ConfigureForm dlgSettings = new ConfigureForm();
                dlgSettings.ShowDialog();
                auth = new DesktopOAuthAuthorization();
                var desktopAuth = (DesktopOAuthAuthorization)auth;
                desktopAuth.ConsumerKey = Settings1.Default.consumerKey;
                desktopAuth.ConsumerSecret = Settings1.Default.consumerSecret;
                
            }
            else
            {
                Console.WriteLine("Discovered Twitter OAuth consumer key in .config file.  Using OAuth authorization.");

                // For OAuth authorization demo...
                auth = new DesktopOAuthAuthorization();
                // If you wanted to pass the consumer key and secret in programmatically, you could do so as shown here.
                // Otherwise this information is pulled out of your .config file.
                var desktopAuth = (DesktopOAuthAuthorization)auth;
                desktopAuth.ConsumerKey = Settings1.Default.consumerKey;
                desktopAuth.ConsumerSecret = Settings1.Default.consumerSecret;

                ////desktopAuth.ConsumerKey = "some key";
                ////desktopAuth.ConsumerSecret = "some secret";
            }
            auth.UseCompression = true;

            // TwitterContext is similar to DataContext (LINQ to SQL) or ObjectContext (LINQ to Entities)

            // For Twitter
            twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/");


            
            // If we're using OAuth, we need to configure it with the ConsumerKey etc. from the user.
            if (twitterCtx.AuthorizedClient is OAuthAuthorization)
            {
                InitializeOAuthConsumerStrings(twitterCtx);
            }

            // Whatever authorization module we selected... sign on now.  
            // See the bottom of the method for sign-off procedures.
            try
            {
                auth.SignOn();
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Login canceled. Demo exiting.");
                return;
            }

            //GetTweets();
            //timer1.Enabled = true;

  
            approveBtn.Enabled = addBtn.Enabled = removeBtn.Enabled = timer1.Enabled = IsConfigured;

            if (IsConfigured) GetTweets();

            Console.WriteLine("Key: " + Settings1.Default.consumerKey);
            GetTweets();
        }

and snipits from the config dialog form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LinqToTwitter;

namespace CCOTweetApprove
{
    public partial class ConfigureForm : Form
    {
        ITwitterAuthorization auth;
        TwitterContext twitterCtx = new TwitterContext();


        public ConfigureForm()
        {
            InitializeComponent();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (DialogResult.Cancel ==
                    MessageBox.Show(this, "CCO TweetAuthorize will now direct you to the Twitter website where " +
                                          "you will be assigned a 7-digit PIN for this application.  Close this box and click the OK button to continue authorization",
                                            "CCO TweetAuthorize", MessageBoxButtons.OKCancel))
                return;
            
            if (String.IsNullOrEmpty(txtConsumerKey.Text) || String.IsNullOrEmpty(txtConsumerSecret.Text))
            {
                MessageBox.Show("You must specify a consumer key and consumer secret.");
            }
            
            //
            Settings1.Default.consumerKey = txtConsumerKey.Text;
            Settings1.Default.consumerSecret = txtConsumerSecret.Text;

            Settings1.Default.Save();

        }

        private void okBtn_Click(object sender, EventArgs e)
        {
            Settings1.Default.consumerKey = txtConsumerKey.Text;
            Settings1.Default.consumerSecret = txtConsumerSecret.Text;
            Settings1.Default.pin = txtPin.Text;

            Settings1.Default.Save();
        }

        private void InitializeOAuthConsumerStrings(TwitterContext twitterCtx)
        {
            Console.WriteLine("just before var oauth");
            var oauth = (DesktopOAuthAuthorization)twitterCtx.AuthorizedClient;

            Console.WriteLine("just before oauth.BeginAuthorize");

            oauth.BeginAuthorize();
            Console.WriteLine("just after oauth.BeginAuthorize");
            oauth.GetVerifier = () =>
            {
                Console.WriteLine("just before return pin");
                

                return Settings1.Default.pin;
            };



            if (oauth.CachedCredentialsAvailable)
            {
                Console.WriteLine("Skipping OAuth authorization step because that has already been done.");

            }
        }


        private void btnAuthorize_Click(object sender, EventArgs e)
        {
            Settings1.Default.consumerKey = txtConsumerKey.Text;
            Settings1.Default.consumerSecret = txtConsumerSecret.Text;
            Settings1.Default.pin = txtPin.Text;
            Settings1.Default.Save();
            
            try
            {
                auth = new DesktopOAuthAuthorization();
                var desktopAuth = (DesktopOAuthAuthorization)auth;
                desktopAuth.ConsumerKey = Settings1.Default.consumerKey;
                desktopAuth.ConsumerSecret = Settings1.Default.consumerSecret;


                auth.UseCompression = true;

                // TwitterContext is similar to DataContext (LINQ to SQL) or ObjectContext (LINQ to Entities)

                // For Twitter
                twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/");



                // If we're using OAuth, we need to configure it with the ConsumerKey etc. from the user.
                if (twitterCtx.AuthorizedClient is OAuthAuthorization)
                {
                    InitializeOAuthConsumerStrings(twitterCtx);
                }

                MessageBox.Show("Congratulations, the application has been authorized!");
            }
            catch(System.Exception ex)
            {
                MessageBox.Show(this, "An error occurred during authorization. Did you provide a valid consumer key and/or secret? Error:\n\n" +                        ex.Message, "CCO TweetAuthorize", MessageBoxButtons.OK);
            }
            
        }

        private void ConfigureForm_Load(object sender, EventArgs e)
        {
            txtConsumerKey.Text = Settings1.Default.consumerKey;
            txtConsumerSecret.Text = Settings1.Default.consumerSecret;
            txtPin.Text = Settings1.Default.pin;

            bool hasConsumerKeyAndSecret = !String.IsNullOrEmpty(txtConsumerKey.Text) &&
                                           !String.IsNullOrEmpty(txtConsumerSecret.Text);

            grpSettings.Enabled = !hasConsumerKeyAndSecret;
            btnSave.Enabled = false;

            if (hasConsumerKeyAndSecret && String.IsNullOrEmpty(Settings1.Default.pin))
            {
                grpAuthorize.Enabled = true;
            }



        }

        private void txtConsumerKeyOrSecret_TextChanged(object sender, EventArgs e)
        {
            btnSave.Enabled = (!String.IsNullOrEmpty(txtConsumerKey.Text) && !String.IsNullOrEmpty(txtConsumerSecret.Text));
        }

        private void resetBtn_Click(object sender, EventArgs e)
        {
            txtConsumerSecret.Enabled = txtConsumerKey.Enabled = true;
            txtConsumerKey.Text = txtConsumerSecret.Text = txtPin.Text = String.Empty;
            grpSettings.Enabled = true;
            grpAuthorize.Enabled = false;
            Settings1.Default.consumerKey = txtConsumerKey.Text;
            Settings1.Default.consumerSecret = txtConsumerSecret.Text;
            Settings1.Default.pin = txtPin.Text;
            Settings1.Default.Save();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            auth = new DesktopOAuthAuthorization();

            var desktopAuth = (DesktopOAuthAuthorization)auth;
            desktopAuth.ConsumerKey = Settings1.Default.consumerKey;
            desktopAuth.ConsumerSecret = Settings1.Default.consumerSecret;


            auth.UseCompression = true;

            twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/");



            // If we're using OAuth, we need to configure it with the ConsumerKey etc. from the user.
            if (twitterCtx.AuthorizedClient is OAuthAuthorization)
            {
                InitializeOAuthConsumerStrings(twitterCtx);
            }

        }
    }
}

Coordinator
Sep 14, 2010 at 1:12 AM

I looked at the code, but don't have time to test it for you, but I do have an observation that might be at the root of your problems.  Look at the DesktopOAuthAuthorization instance you're working with. It isn't the same instance throughout your application. Sometimes you're accessing a class field and other times you're working with a local variable.  It's important that you work with the same instance, which should probably be held in a field or property since you're working with it accross multiple methods.

Joe

Sep 14, 2010 at 2:24 AM

Joe, thank you very much!  It looks like I was making this way toooooo complicated.  As soon as you said to look at the various desktopauthorizations I was using, and talking about local vs class variables, I realized

I was making the Configuration form an entire seperate ouath experience.  All I need to do is just make 3 public variabels on the config form...key, secret and pin... and grab them from the main form.

the buttonclick event at the bottom was my first attempt to test it..and that actually worked as everything was local to that event.   As soon as I tried to call the config form as a dialog, I made that form almost

stand alone.. 

I will rework and simplify this tomorrow.  I am still learning C# and .net as well as trying to grapple with linq2twitter.   It is projects like this that help me learn...as well as your book which I own :)

thank you for the second set of eyes on my wild code lol.

Sep 14, 2010 at 6:47 PM

Joe and or the linq2twitter community,

I have a new issue with this small app.  The code inside the Lambda never executes.  Because of this, I get:

System.Net.WebException was unhandled
  Message=The remote server returned an error: (401) Unauthorized.
  Source=System
  StackTrace:
       at System.Net.HttpWebRequest.GetResponse()
       at LinqToTwitter.OAuthAuthorization.ValidateLogin() in C:\Projects\LinqToTwitter\LinqToTwitter\OAuth\OAuthAuthorization.cs:line 255
       at LinqToTwitter.OAuthAuthorization.SignOn() in C:\Projects\LinqToTwitter\LinqToTwitter\OAuth\OAuthAuthorization.cs:line 160
       at CCOTweetApprove.TweetApprove.Form1_Shown(Object sender, EventArgs e) in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\TweetApprove.cs:line 167
       at System.Windows.Forms.Form.OnShown(EventArgs e)
       at System.Windows.Forms.Form.CallShownEvent()
       at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at CCOTweetApprove.Program.Main() in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

 

 I see the Console.Writeline showing "just before oauth.Getverifier"

but the "within oauth.GetVerifier" never displays.

Just after the Lambda, I do get: From InitializeOAuthConsumerStrings(TwitterContext twitterCtx) Skipping OAuth authorization step because that has already been done."

via Console.Writeline

Just prior to the call to InitializeOAuthConsumerStrings, I do show the key and secret via Console.Writelines.  I must be missing something simple...My code is below:

        private static void InitializeOAuthConsumerStrings(TwitterContext twitterCtx)
        {
            Console.WriteLine("just before oauth.GetVerifier");
            
            var oauth = (DesktopOAuthAuthorization)twitterCtx.AuthorizedClient;
            oauth.GetVerifier = () =>
                {

                    Console.WriteLine("within oauth.GetVerifier");

                    ConfigureForm dlgSettings = new ConfigureForm();

                       if (string.IsNullOrEmpty(Settings1.Default.pin))
                       {
                           
                           dlgSettings.ShowDialog();
                       }

                       Console.WriteLine("pin after config from" + dlgSettings.consumerPin);

                       return Settings1.Default.pin;
                };

            

            if (oauth.CachedCredentialsAvailable)
            {
                Console.WriteLine("From InitializeOAuthConsumerStrings(TwitterContext twitterCtx) Skipping OAuth authorization step because that has already                  been done.");
            }
        }
        



        private void Form1_Shown(object sender, EventArgs e)
        {
            
            Console.WriteLine("loading key from form shown: " + Settings1.Default.consumerKey);
            Console.WriteLine("loading secret from form shown: " + Settings1.Default.consumerSecret);
            Console.WriteLine("loading pin from form shown: " + Settings1.Default.pin);

            if (string.IsNullOrEmpty(Settings1.Default.consumerKey) || string.IsNullOrEmpty(Settings1.Default.consumerSecret))
            {
                Console.WriteLine("Skipping OAuth authorization demo because twitterConsumerKey and/or twitterConsumerSecret are not set in your .config                      file.");
                Console.WriteLine("Loading Config Page instead");

                ConfigureForm dlgSettings = new ConfigureForm();
                dlgSettings.ShowDialog();

                Console.WriteLine("loading key after entering from config: " + Settings1.Default.consumerKey);
                Console.WriteLine("loading secret after entering from config: " + Settings1.Default.consumerSecret);
            }
            else
            {
                Console.WriteLine("Discovered Twitter OAuth consumer key in .config file.  Using OAuth authorization.");

                auth = new DesktopOAuthAuthorization();
                var desktopAuth = (DesktopOAuthAuthorization)auth;
                desktopAuth.ConsumerKey = Settings1.Default.consumerKey;
                desktopAuth.ConsumerSecret = Settings1.Default.consumerSecret;
            
            }
            auth.UseCompression = true;

            // TwitterContext is similar to DataContext (LINQ to SQL) or ObjectContext (LINQ to Entities)

            // For Twitter
            using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/"))
            {
                // If we're using OAuth, we need to configure it with the ConsumerKey etc. from the user.
                if (twitterCtx.AuthorizedClient is OAuthAuthorization)
                {
                    Console.WriteLine("Just before InitializeOAuthConsumerStrings after else in form shown");
                    InitializeOAuthConsumerStrings(twitterCtx);
                }

                // Whatever authorization module we selected... sign on now.  
                // See the bottom of the method for sign-off procedures.
                try
                {
                    auth.SignOn();
                }
                catch (OperationCanceledException)
                {
                    Console.WriteLine("Login canceled. Demo exiting.");
                    return;
                }
            }


  
            approveBtn.Enabled = addBtn.Enabled = removeBtn.Enabled = timer1.Enabled = IsConfigured;

            if (IsConfigured) GetTweets();

        }

Sep 14, 2010 at 7:09 PM

I rebooted, and ran the app again...now the code inside the Lambda did run..  does this indicate it had some sort of cached credentials??  If so, how do you clear that?

as soon as I started the app, it took me out to the twitter pin page..   up came my config screen, I put my pin in...saved it... closed the dialog...and when it returned to the main form I got this exception:

System.Reflection.TargetInvocationException was unhandled
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
       at LinqToTwitter.TwitterQueryProvider.Execute[TResult](Expression expression) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterQueryProvider.cs:line 110
       at LinqToTwitter.TwitterQueryable`1.GetEnumerator() in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterQueryable.cs:line 102
       at CCOTweetApprove.TweetApprove.GetTweets() in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\TweetApprove.cs:line 201
       at CCOTweetApprove.TweetApprove.Form1_Shown(Object sender, EventArgs e) in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\TweetApprove.cs:line 174
       at System.Windows.Forms.Form.OnShown(EventArgs e)
       at System.Windows.Forms.Form.CallShownEvent()
       at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at CCOTweetApprove.Program.Main() in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: LinqToTwitter.TwitterQueryException
       Message=Error while querying Twitter.
       Source=LinqToTwitter
       HttpError=401 Unauthorized
       StackTrace:
            at LinqToTwitter.TwitterExecute.QueryTwitter(String url) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterExecute.cs:line 280
            at LinqToTwitter.TwitterContext.Execute[T](Expression expression, Boolean isEnumerable) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterContext.cs:line 519
       InnerException: System.Net.WebException
            Message=The remote server returned an error: (401) Unauthorized.
            Source=System
            StackTrace:
                 at System.Net.HttpWebRequest.GetResponse()
                 at LinqToTwitter.TwitterExecute.QueryTwitter(String url) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterExecute.cs:line 273
            InnerException:

 

Running the app again shows the same exception.  I do indeed have the key, the secret and the pin at the startup of the app.

 

 

Sep 14, 2010 at 7:23 PM

Upon further review, the exception is called with my GetTweets() method...   so I am not so sure the app is authorized...looking at my twitter page it does show it is registered...

 

        private void GetTweets()
        {

            //listBox1.Items.Clear();
            tweetList.Clear();
            
            

            var friendTweets =
                    from tweet in twitterCtx.Status
                    where tweet.Type == StatusType.Home
                    select tweet;

            foreach (var tweet in friendTweets)
            {
               //listBox1.Items.Add(tweet.User.Name + ": " + tweet.Text + "\r\n");
                tweetList.Add(tweet.User.Name + ": " + tweet.Text + "\r\n");
                
            }

            //listBox1.DataSource = tweetList;
            ApplyDataBinding();
        }

Coordinator
Sep 14, 2010 at 7:32 PM

Here's a couple things you can do in the debugging process:

1. Try your tokens with the sample app, the LinqToTwitterDemo project.  If this works, you know your tokens are good.

2. Use Fiddler to watch traffic with LinqToTwitterDemo.  This will show you what requests are being made and the responses.  Remember to turn off encryption, which I think is the default in recent versions, but this helps you see the text.

3. Run your own app, watching Fiddler, to see the difference.  This will tell you if you're performing the proper actions in the right sequence or missing some actions.

4. Add the LinqToTwitter project to your solution and step through the code, watching the OAuth calls and observe how caching and execution occurs.  This might provide insight into what's happening. Compare this to the LinqToTwitterDemo sequence.

Joe

Sep 15, 2010 at 12:23 AM

well I have done quite a bit of testing.   The keys do indeed work on the demo app.  From what I can tell via Fiddler...my app is either not storing the pin or sending it properly. 

One question I have...if the demo app works and is authorized..  will twitter ignore a second app (such as my app) that uses the same keys?  I would think not.

other than the fact that the demo app gets the pin via Console.Readline and mine gets it from a dialog box, I believe my code is virtually identical to the demo app.  I will post the entire code below as well as

the exception that I get after closing the dialog.  The dialog is just a form with one text field and the OK button.  I am seeing the pin that is entered show up with a Console.Writeline so I know I am indeed

grabbing the pin...  I return the very same pin in the Lambda.

 

Also I noticed, that if I reboot, and run my app again, it takes me out to the twitter pin page each time...I again put the pin in the dialog and click ok... so that is why I suspect something is wrong with

how I am obtaining the pin.  ONLY after a reboot does it take me out there...if I do not reboot, it keeps giving the exception below.  I am not sure why I have to reboot to recreate this.  something is getting

cached somewhere but I have no idea where.

Exception below, code after that:

System.Reflection.TargetInvocationException was unhandled
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
       at LinqToTwitter.TwitterQueryProvider.Execute[TResult](Expression expression) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterQueryProvider.cs:line 110
       at LinqToTwitter.TwitterQueryable`1.GetEnumerator() in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterQueryable.cs:line 102
       at CCOTweetApprove.TweetApprove.GetTweets() in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\TweetApprove.cs:line 212
       at CCOTweetApprove.TweetApprove.Form1_Shown(Object sender, EventArgs e) in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\TweetApprove.cs:line 185
       at System.Windows.Forms.Form.OnShown(EventArgs e)
       at System.Windows.Forms.Form.CallShownEvent()
       at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at CCOTweetApprove.Program.Main() in C:\Users\ccisat1cjc\Documents\Visual Studio 2010\Projects\TwitterTest\TwitterTest\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: LinqToTwitter.TwitterQueryException
       Message=Error while querying Twitter.
       Source=LinqToTwitter
       HttpError=401 Unauthorized
       StackTrace:
            at LinqToTwitter.TwitterExecute.QueryTwitter(String url) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterExecute.cs:line 280
            at LinqToTwitter.TwitterContext.Execute[T](Expression expression, Boolean isEnumerable) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterContext.cs:line 519
       InnerException: System.Net.WebException
            Message=The remote server returned an error: (401) Unauthorized.
            Source=System
            StackTrace:
                 at System.Net.HttpWebRequest.GetResponse()
                 at LinqToTwitter.TwitterExecute.QueryTwitter(String url) in C:\Projects\LinqToTwitter\LinqToTwitter\LinqToTwitter\TwitterExecute.cs:line 273
            InnerException:

and now the code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Net;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LinqToTwitter;
using System.Configuration;
using System.Net.Mail;
using System.Collections;






namespace CCOTweetApprove
{
    public partial class TweetApprove : Form
    {
        ITwitterAuthorization auth;
        TwitterContext twitterCtx = new TwitterContext();
        static bool mailSent;
        ArrayList tweetList = new ArrayList();
        string currentItemText;
        int currentItemIndex;
       

        public bool IsConfigured
        {
            get
            {
                return !String.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerKey"]) &&
                    !String.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerSecret"]);
                    
            }
        }
       
        
       

        public TweetApprove()
        {
            
            InitializeComponent();
        }

        private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
        {
            // Get the unique identifier for this asynchronous operation.
            String token = (string)e.UserState;

            if (e.Cancelled)
            {
                Console.WriteLine("[{0}] Send canceled.", token);
            }
            if (e.Error != null)
            {
                Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
            }
            else
            {
                Console.WriteLine("Message sent.");
                
            }
            mailSent = true;
            
        }

        

        private static void InitializeOAuthConsumerStrings(TwitterContext twitterCtx)
        {
            Console.WriteLine("just before oauth.GetVerifier");
            
            var oauth = (DesktopOAuthAuthorization)twitterCtx.AuthorizedClient;
            oauth.GetVerifier = () =>
                {

                    Console.WriteLine("within oauth.GetVerifier");

                    ConfigureForm dlgSettings = new ConfigureForm();


                    dlgSettings.ShowDialog();

                       Console.WriteLine("pin after config form: " + dlgSettings.consumerPin);
                       string pin = dlgSettings.consumerPin;
                       
                       return pin;
                };

            

            if (oauth.CachedCredentialsAvailable)
            {
                Console.WriteLine("From InitializeOAuthConsumerStrings(TwitterContext twitterCtx) Skipping OAuth authorization step because that has already                  been done.");
            }
        }
        



        private void Form1_Shown(object sender, EventArgs e)
        {

            Console.WriteLine("loading key from form shown: " + ConfigurationManager.AppSettings["twitterConsumerKey"]);
            Console.WriteLine("loading secret from form shown: " + ConfigurationManager.AppSettings["twitterConsumerSecret"]);
            //Console.WriteLine("loading pin from form shown: " + Settings1.Default.pin);

            //if (string.IsNullOrEmpty(Settings1.Default.consumerKey) || string.IsNullOrEmpty(Settings1.Default.consumerSecret))
            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerKey"]) || string.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerSecret"]))
            {
                //future code below:
                /*
                Console.WriteLine("Skipping OAuth authorization demo because twitterConsumerKey and/or twitterConsumerSecret are not set in your .config                      file.");
                Console.WriteLine("Loading Config Page instead");

                ConfigureForm dlgSettings = new ConfigureForm();
                dlgSettings.ShowDialog();

                Console.WriteLine("loading key after entering from config: " + ConfigurationManager.AppSettings["twitterConsumerKey"]);
                Console.WriteLine("loading secret after entering from config: " + ConfigurationManager.AppSettings["twitterConsumerSecret"]);
                 */
            }
            else
            {

                Console.WriteLine("Discovered Twitter OAuth consumer key in .config file.  Using OAuth authorization.");

                auth = new DesktopOAuthAuthorization();
                //var desktopAuth = (DesktopOAuthAuthorization)auth;
                //desktopAuth.ConsumerKey = Settings1.Default.consumerKey;
                //desktopAuth.ConsumerSecret = Settings1.Default.consumerSecret;
            }


                auth.UseCompression = true;

                // TwitterContext is similar to DataContext (LINQ to SQL) or ObjectContext (LINQ to Entities)

                // For Twitter
                using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/"))
                {
                    // If we're using OAuth, we need to configure it with the ConsumerKey etc. from the user.
                    if (twitterCtx.AuthorizedClient is OAuthAuthorization)
                    {
                        Console.WriteLine("Just before InitializeOAuthConsumerStrings after else in form shown");
                        InitializeOAuthConsumerStrings(twitterCtx);
                    }

                    // Whatever authorization module we selected... sign on now.  
                    // See the bottom of the method for sign-off procedures.
                    try
                    {
                        Console.WriteLine("Trying SignOn");
                        auth.SignOn();
                    }
                    catch (OperationCanceledException)
                    {
                        Console.WriteLine("Login canceled. Demo exiting.");
                        return;
                    }
                }
            
            approveBtn.Enabled = addBtn.Enabled = removeBtn.Enabled = timer1.Enabled = IsConfigured;

            if (IsConfigured) GetTweets();

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            StatusLabel1.Text = "Updating....";

            GetTweets();

            StatusLabel1.Text = "Last Updated: " + DateTime.Now.ToString();

        }

        private void GetTweets()
        {

            //listBox1.Items.Clear();
            tweetList.Clear();
            
            

            var friendTweets =
                    from tweet in twitterCtx.Status
                    where tweet.Type == StatusType.Home
                    select tweet;

            foreach (var tweet in friendTweets)
            {
               //listBox1.Items.Add(tweet.User.Name + ": " + tweet.Text + "\r\n");
                tweetList.Add(tweet.User.Name + ": " + tweet.Text + "\r\n");
                
            }

            //listBox1.DataSource = tweetList;
            ApplyDataBinding();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {

            //mailSent = false;

            string body = "";
             MailMessage mail = new MailMessage("CCOTwitterApprovals@ClearChannel.com", "ChuckCondron@ClearChannel.com");


            mail.Subject = "Twitter Approvals";

 


            for(int i = 0; i < listBox2.Items.Count; i++)
                {
                body += listBox2.Items[i].ToString() +"\r\n";
                }

            Console.WriteLine(body);
            mail.Body = body;

            SmtpClient sc = new SmtpClient("relay.clearchannel.com");

            // Set the method that is called back when the send operation ends.
            sc.SendCompleted += new
            SendCompletedEventHandler(SendCompletedCallback);
            // The userState can be any object that allows your callback 
            // method to identify this send operation.
            // For this example, the userToken is a string constant.
            string userState = "test message1";
           
            int temp = ServicePointManager.MaxServicePointIdleTime; //<- Store the original value. 
            ServicePointManager.MaxServicePointIdleTime = 1; 

            try
            {
                sc.SendAsync(mail, userState);
                //sc.Send(mail);

            }

            catch (SmtpException ex)
            {

                MessageBox.Show(ex.Message, "Error: " + ex.Message, MessageBoxButtons.OK,                                 MessageBoxIcon.Error);

            }
            finally
            {
                ServicePointManager.MaxServicePointIdleTime = temp; //<- Set the idle time back to what it was. 
            } 
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //original...listBox2.Items.Add(listBox1.SelectedItem.ToString());
            // Find the right item and it's value and index
            currentItemText = listBox1.SelectedValue.ToString();
            currentItemIndex = listBox1.SelectedIndex;

            listBox2.Items.Add(currentItemText);
            if (tweetList != null)
            {
                tweetList.RemoveAt(currentItemIndex);
            }

            // Refresh data binding
            ApplyDataBinding();
        }

        private void ApplyDataBinding()
        {
            listBox1.DataSource = null;
            // Bind ArrayList with the ListBox
            listBox1.DataSource = tweetList;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            auth.SignOff();
        }

        private void RemoveButton_Click(object sender, EventArgs e)
        {
            // Find the right item and it's value and index
            currentItemText = listBox2.SelectedItem.ToString();
            currentItemIndex = listBox2.SelectedIndex;
            // Add RightListBox item to the ArrayList
            tweetList.Add(currentItemText);

            // LeftListBox.Items.Add(RightListBox.SelectedItem);
            listBox2.Items.RemoveAt(listBox2.Items.IndexOf(listBox2.SelectedItem));

            // Refresh data binding
            ApplyDataBinding();
             

           

        }

        private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBox2.SelectedIndex != -1)
            {
                Console.WriteLine(listBox2.SelectedItem.ToString());
            }
        }

        private void button2_Click_1(object sender, EventArgs e)
        {
            tweetList.Clear();
            listBox1.DataSource = null;
            listBox1.DataSource = tweetList;
        }


        private void configureBtn_Click(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            ConfigureForm dlgSettings = new ConfigureForm();
            if (DialogResult.OK == dlgSettings.ShowDialog())
            {
                approveBtn.Enabled = addBtn.Enabled = removeBtn.Enabled = timer1.Enabled = IsConfigured;
            }
        }

    }
}

Sep 15, 2010 at 7:30 PM

I FINALLY figured it out...  I changed the declaration at the top from

TwitterContext twitterCtx = new TwitterContext();

to

TwitterContext twitterCtxGT = new TwitterContext();

then I made changed my GetTweets() to GetTweets(TwitterContext twitterCtxGT)

in the form shown, after authentication was done, I set twitterCtxGT = to twitterCtx. and I call GetTweets(twitterCtxGT).

I think having the declaration of twitterCtx as a class variable for the authentication was messing things up...  that was the ONLY difference I saw in my code vs the demo...and of course the call to the dialog

box instead of the Console.Readline();

So...  I hope all of this helps someone.   If anyone see anything else wrong, let me know.  so far so good.

 Thank you Joe!