mikeo_410


Silverlight の入出力


  お菓子検索のサンプルを作りながら、ブラウザの内側のSilverlight アプリケーションがどう外界とやり取りするのかをまとめて見ました。
  お菓子検索のサンプルプログラムは、左図をクリックするとポップアップウインドウを開いて実行します。
  お菓子の虜 Web API の検索機能を使っています。

1.Silverlight アプリケーションの実行と入出力

  Silverlight アプリケーションは、ブラウザを実行しているクライアント側で実行されるプログラムです。
  サーバーの動作は、通常の http サーバの動作です。http サーバは、要求されたファイルをブラウザへ送ります。Web APIのように、サーバー上でプログラムが、XMLなどのストリームを作って返す動作もしますが、要求も応答もファイルのときの動作を模倣したものです。
  Silverlight アプリケーションは、XAPファイルとそれをホストするHTMLファイルからできています。サーバーは、これを格納していて、ブラウザからの要求に応じて送信します。
  サーバーはファイルの内容には関与しないので、サーバの OS や CPU は、まったく動作に関係しません。

  ブラウザ側で実行している Silverlight プログラムは、ブラウザ側のパソコンに被害を与えないように、分離された環境で実行されます。どのように「分離」されているかと言うと、ファイルの入出力に制限が付けられています。
  機能的には、アップロードもダウンロードもできるのですが、ブラウザ側で、ユーザが操作して選んだり、指定したファイル以外はアクセスできないようになっています。プログラムが自律的に、ファイルをアクセスすることはできません。
  また、ファイルが他のサーバにある場合、そのサーバに明示的な許可が設定されていないとアクセスしないような仕組みがあります。

  これらを前提にして考えると、Silverlight アプリケーションの入出力は、4つに分けるのが理解し易そうです。

2.展開フォルダの入出力

  正式な名称は分かりませんが、XAPにパッケージングされているファイルは、展開して使われるはずです。
  XAP ファイルには、プログラム(DLLなど)が格納されていますが、プログラムで使うためのデータを含めることができます。ここでは、プログラムの作成時に追加したデータファイルのアクセス方法を挙げます。

2.1.埋め込まれたリソース

  Visual Studio のプロジェクトに追加したファイルのプロパティの「ビルドアクション」に「埋め込まれたリソース」があります。これを指定すると、DLL中に埋め込まれます。
  例では、イメージを読み込んで、Imageクラスのソースにして表示しています。
  イメージ・ファイル名の前に、ファイルを含めたプロジェクト(アセンブリ)のネームスペースが付きます。

  1. Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("namespace.logo.png");
  2. BitmapImage bi = new BitmapImage();
  3. bi.SetSource(stream);
  4. image1.Source = bi;

2.2.ビルドアクションで「Resource」を指定したファイル

  「埋め込まれたリソース」にしなくても、同じようにDLL中に含まれるようです 。
  「埋め込まれたリソース」と「Resource」の使い方を「Silverlightのマニフェスト・リソース」に書きます。

2.3.コンテンツ

  Visual Studio のプロジェクトに追加したファイルのプロパティの「ビルドアクション」に「コンテンツ」があります。これを指定すると、XAPファイルの中に、独立したファイルのままパッケージングされます。
  例では、イメージを読み込んで、Imageクラスのソースにして表示しています。

  1. System.Windows.Resources.StreamResourceInfo sri = App.GetResourceStream(new Uri("logo.png",UriKind.Relative));
  2. BitmapImage bi = new BitmapImage();
  3. bi.SetSource(sri.Stream);
  4. image1.Source = bi;

2.4.XAPの参照

  XmlXapResolver で、参照できるようです。

  1. XmlXapResolver xxr = new XmlXapResolver();
  2. object obj = xxr.GetEntity(new Uri("logo.png", UriKind.Relative), null, typeof(Stream));
  3. Stream stream = obj as Stream;
  4. BitmapImage bi = new BitmapImage();
  5. bi.SetSource(stream);
  6. image1.Source = bi;

3.パソコン内のファイルのアクセス

  ブラウザを実行しているパソコンのファイルには、OpenFileDialog、SaveFileDialog でのみアクセスできます。
  このダイアログは、プログラムでいつでも開けるわけではなく、ボタンをユーザが押したときの処理の中など、操作したタイミングでだけ開けるようになっています。
  ファイルのダウンロード、アップロードに対応した処理を記述することが想定されているものと思います。

  その他のファイル関連のクラスは隠されておらず、そのままプログラミングできるようになっています。実行時にエラーになります。

4.分離ストレージ

  2つの目的があるようです。

  1. 一時ファイルとして
  2. 永続ストレージとして

  作成できるファイルのサイズには制限があり、後者が主要な目的のようです。
  一度作ったファイルは消さない限り残るので、アプリケーションで一時ファイルに使うなら配慮する必要があります。
  IsolatedStorageには、Site と Application の2種類があります。
  ブラウザ側に Silverlight アプリケーション空間が作られると言ったイメージのようです。

  このストレージは、Silverlight アプリケーション以外からは隠されています。
  エクスプローラ等で表示することはできないようです。

4.1.分離ストレージのサンプル

  

  左図をクリックすると、ポップアップウインドウでプログラムが実行されます。

  このプログラムは、Site と Application のファイルを列挙します。
  また、表示の後で、Site と Application に、1つずつファイルを作っています。

  最初に起動すると、ファイルがない状態で表示されます。
  ポップアップウインドウを閉じて、再度、左の図をクリックして開きなおします。
  すると、最初に開いたときに作られたファイルが表示されます。
  その後、ページの再表示やブラウザの「更新」の度にファイルが増えていきます。

  このストレージは永続的なものだと言うことです。 

  (ここで作られるファイルの削除方法は後の方で記述します。) 

  この例のプログラムは、以下の通りです。

  1. <UserControl x:Class="sla_isolatedStorage1.Page"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     Width="400" Height="300">
  5.     <Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
  6.         <StackPanel>
  7.             <Image x:Name="image1" Width="32" Height="32"/>
  8.             <ListBox x:Name="listBox1"/>
  9.         </StackPanel>
  10.     </Grid>
  11. </UserControl>

  1. private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     //これは、サーバーからの動的ダウンロードになる
  4.     BitmapImage bi = new BitmapImage(new Uri("cherry.png", UriKind.Relative));
  5.     image1.Source = bi;
  6.     //分離ストレージ(Application)のファイルをリストボックスに列挙する
  7.     IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
  8.     string[] fns = isf.GetFileNames();
  9.     listBox1.Items.Add("Application のファイル");
  10.     foreach (string fn in fns)
  11.         listBox1.Items.Add(fn);
  12.     //分離ストレージ(Application)に連番のファイル名のファイルを作る
  13.     isf.CreateFile(fns.Length.ToString() + ".app");
  14.     //分離ストレージ(Site)のファイルをリストボックスに列挙する
  15.     isf = IsolatedStorageFile.GetUserStoreForSite();
  16.     fns = isf.GetFileNames();
  17.     listBox1.Items.Add("Site のファイル");
  18.     foreach (string fn in fns)
  19.         listBox1.Items.Add(fn);
  20.     //分離ストレージ(Site)に連番のファイル名のファイルを作る
  21.     isf.CreateFile(fns.Length.ToString() + ".site");
  22. }

mikeo_410@hotmail.com