2010年1月25日月曜日

第8回 認証が必要なタイムラインにアクセスする

これまでユーザーIDとパスワードが必要なタイムラインへのアクセスを避けていたので
今回はそこを作ります。

まずユーザーIDとパスワードを保持するクラスを作ります。



namespace WTwitter.Model.UserData {
 /// <summary>
 /// ログイン情報を保持するクラス
 /// </summary>
 public class UserInfo {
  public string UserName { get; set; }
  public string Password { get; set; }
 }
}



本当はパスワードにはセキュリティのためSecureStringクラスとかを使った方がいいのですが、
今回は簡便化のためふつうのstringにしています。

次にIDとパスワードを入力するためのダイアログ(ウィンドウ)を作ります。



<Window x:Class="WTwitter.View.OptionDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="オプション設定" Width="190" Height="120" Loaded="Window_Loaded">
 <Window.BindingGroup>
  <BindingGroup/>
 </Window.BindingGroup>
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
  <Grid.ColumnDefinitions>
   <ColumnDefinition Width="Auto"/>
   <ColumnDefinition Width="Auto"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
   <RowDefinition Height="Auto"/>
   <RowDefinition Height="Auto"/>
   <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <TextBlock Text="UserName" Grid.Row="0" Grid.Column="0"/>
  <TextBox Grid.Row="0" Text="{Binding Path=UserName}"
     Grid.Column="1" Width="100"/>
  
  <TextBlock Text="Password" Grid.Row="1" Grid.Column="0"/>
  <TextBox Text="{Binding Path=Password}"
   Grid.Row="1" Grid.Column="1" Width="100"/>
  
  <Button Grid.Row="2" Grid.Column="1" IsDefault="True" Click="OkButton_Click">OK(_O)</Button>
    </Grid>
</Window>






 public partial class OptionDialog : Window {
  public OptionDialog(UserInfo target) {
   this.DataContext = target;
   InitializeComponent();
  }

  private void Window_Loaded(object sender, RoutedEventArgs e) {
   BindingGroup.BeginEdit();
  }

  private void OkButton_Click(object sender, RoutedEventArgs e) {
   BindingGroup.CommitEdit();
   this.Close();
  }
 }



ちょっと前回まで説明が長かったので、今回からさくっと説明します。
適宜コメントか検索で。

XAMLの方。
ダイアログは2列×3行のGrid(表みたいな入れ物)を作ってテキストボックスなどを配置しています。
先ほど作ったUserInfoクラスをDataContextに入れるので、
それぞれのテキストボックスはUserInfoクラスのプロパティへのパスを指定しています。
WindowにBindingGroupを作っています。
これがあるとBindingGroup.CommitEdit()を呼び出したときに
テキストボックスの中身がUserInfoのプロパティに反映されます。

コードビハインド(.cs)の方はその呼び出しだけです。

あとはApp.xaml.csを以下のように変更しました。
これまでのWindow1クラスは名前が適当すぎたので新しくMainWindowクラスを作りました。
そしてダイアログを通じてUserInfoを取得してもらって、
それをメインウィンドウに渡しています。



 public partial class App : Application {

  protected override void OnStartup(StartupEventArgs e) {
   base.OnStartup(e);

   //最初に作ったWindowがApplication.MainWindowに設定されるので、OptionDialogより先に作る
   var mainWindow = new MainWindow();

   var userInfo = new UserInfo();
   OptionDialog dialog = new OptionDialog(userInfo);
   dialog.ShowDialog();

   mainWindow.Initialize(userInfo);
   mainWindow.Show();
  }
 }




最後にこのIDとパスワードはTimelineまで伝わって
NetworkCredentialクラスを作り
requestに追加することで認証を通しています。



  public Timeline(string timelineURL, string userName, string password) {
   _url = timelineURL;
   _credential = new NetworkCredential(userName, password);
   StatusAdded += (sender, e) => { }; //あとでnullチェックしないですむように
  }


  /// Twitterサーバからデータを取得する
  /// </summary>
  public void Update() {
   //HTTP用の要求と応答
   HttpWebRequest request = HttpWebRequest.Create(_url) as HttpWebRequest;
   //認証情報を付加する
   if (_credential != null) {
    request.Credentials = _credential;
   }
   HttpWebResponse response = request.GetResponse() as HttpWebResponse;



MainWindowViewModelで設定するタイムラインには
ユーザタイムラインとフレンドタイムラインを表示するように変更してみました。



   var list = new List<TimelineViewModel>() {
    new TimelineViewModel("Friends",
     new Timeline("http://twitter.com/statuses/friends_timeline.json", _userInfo.UserName, _userInfo.Password)),
    new TimelineViewModel( "User",
     new Timeline(string.Format("http://twitter.com/statuses/user_timeline/{0}.json",_userInfo.UserName))),
   };




認証が失敗したときとかの処理を全然していませんが、今回はこれまで。
コードはこちら。
http://wtwitter.codeplex.com/SourceControl/changeset/view/39193

1 件のコメント:

  1. バグのご指摘をいただきました。
    Timelineの2つのコンストラクタで整合がとれていませんでした。
    3つの引数をとる方のコンストラクタは
    UserIdやパスワードが入っていなかったら
    Credentialをnullのままにするように変更してください。

    返信削除