StreamingFeeds サンプルは、多数の項目を含む配信フィードを管理する方法を示しています。 このサンプルでは、サーバー上で、アイテムがネットワーク ストリームに書き込まれる直前まで、フィード内の個々の SyndicationItem オブジェクトの作成を遅延させる方法を示します。
クライアントでは、カスタム シンジケーション フィード フォーマッタを使用してネットワーク ストリームから個々の項目を読み取り、読み取られるフィードがメモリに完全にバッファーされないようにする方法を示します。
配信 API のストリーミング機能を最もよく示すために、このサンプルでは、サーバーが無限の数の項目を含むフィードを公開する、やや可能性の低いシナリオを使用します。 この場合、サーバーは、クライアントがフィードから指定された数のアイテム (既定では 10) を読み取ったと判断されるまで、フィードに新しい項目を生成し続けます。 わかりやすくするために、クライアントとサーバーの両方が同じプロセスで実装され、共有 ItemCounter
オブジェクトを使用して、クライアントが生成した項目の数を追跡します。
ItemCounter
型は、サンプル シナリオをクリーンに終了できるようにするためにのみ存在し、示されているパターンのコア要素ではありません。
このデモでは、( yield return
キーワード コンストラクトを使用して) Visual C# 反復子を使用します。 反復子の詳細については、MSDN の「反復子の使用」トピックを参照してください。
サービス
サービスは、次のコードに示すように、1 つの操作で構成される基本的な WebGetAttribute コントラクトを実装します。
[ServiceContract]
interface IStreamingFeedService
{
[WebGet]
[OperationContract]
Atom10FeedFormatter StreamedFeed();
}
サービスは、次のコードに示すように、 ItemGenerator
クラスを使用して、反復子を使用して SyndicationItem インスタンスの無限ストリームを作成することで、このコントラクトを実装します。
class ItemGenerator
{
public IEnumerable<SyndicationItem> GenerateItems()
{
while (counter.GetCount() < maxItemsRead)
{
itemsReturned++;
yield return CreateNextItem();
}
}
...
}
サービス実装がフィードを作成すると、バッファーに格納された項目のコレクションではなく、 ItemGenerator.GenerateItems()
の出力が使用されます。
public Atom10FeedFormatter StreamedFeed()
{
SyndicationFeed feed = new SyndicationFeed("Streamed feed", "Feed to test streaming", null);
//Generate an infinite stream of items. Both the client and the service share
//a reference to the ItemCounter, which allows the sample to terminate
//execution after the client has read 10 items from the stream
ItemGenerator itemGenerator = new ItemGenerator(this.counter, 10);
feed.Items = itemGenerator.GenerateItems();
return feed.GetAtom10Formatter();
}
その結果、項目ストリームがメモリに完全にバッファリングされることはありません。 この動作を確認するには、ItemGenerator.GenerateItems()
メソッド内の yield return
ステートメントにブレークポイントを設定し、サービスが StreamedFeed()
メソッドの結果を返した後、このブレークポイントが初めて発生することを確認します。
顧客
このサンプルのクライアントは、カスタム SyndicationFeedFormatter 実装を使用します。この実装では、個々の項目をメモリにバッファーするのではなく、フィード内の個々の項目の具体化を遅らせることができます。 カスタム StreamedAtom10FeedFormatter
インスタンスは、次のように使用されます。
XmlReader reader = XmlReader.Create("http://localhost:8000/Service/Feeds/StreamedFeed");
StreamedAtom10FeedFormatter formatter = new StreamedAtom10FeedFormatter(counter);
SyndicationFeed feed = formatter.ReadFrom(reader);
通常、 ReadFrom(XmlReader) の呼び出しは、フィードの内容全体がネットワークから読み取られ、メモリにバッファーされるまで戻りません。 ただし、次のコードに示すように、 StreamedAtom10FeedFormatter
オブジェクトは、バッファー内のコレクションではなく反復子を返す ReadItems(XmlReader, SyndicationFeed, Boolean) をオーバーライドします。
protected override IEnumerable<SyndicationItem> ReadItems(XmlReader reader, SyndicationFeed feed, out bool areAllItemsRead)
{
areAllItemsRead = false;
return DelayReadItems(reader, feed);
}
private IEnumerable<SyndicationItem> DelayReadItems(XmlReader reader, SyndicationFeed feed)
{
while (reader.IsStartElement("entry", "http://www.w3.org/2005/Atom"))
{
yield return this.ReadItem(reader, feed);
}
reader.ReadEndElement();
}
その結果、 ReadItems()
の結果を走査するクライアント アプリケーションで使用できる状態になるまで、各項目はネットワークから読み取られるわけではありません。 この動作を確認するには、StreamedAtom10FeedFormatter.DelayReadItems()
内の yield return
ステートメントにブレークポイントを設定し、ReadFrom()
の呼び出しが完了した後にこのブレークポイントが初めて発生することに気付きます。
次の手順では、サンプルをビルドして実行する方法を示します。 クライアントが 10 個の項目を読み取った後、サーバーは項目の生成を停止しますが、出力はクライアントが 10 項目を大幅に超える項目を読み取っていることを示しています。 これは、サンプルで使用されるネットワーク バインディングによって、データが 4 KB (KB) セグメントで送信されるためです。 そのため、クライアントは、1 つの項目を読み取る機会を得る前に、4 KB の項目データを受け取ります。 これは通常の動作です (ストリーミングされた HTTP データを適切なサイズのセグメントで送信すると、パフォーマンスが向上します)。
サンプルを設定、ビルド、実行するには
Windows Communication Foundation サンプル のOne-Time セットアップ手順を実行していることを確認します。
ソリューションの C# または Visual Basic .NET エディションをビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。
単一または複数のコンピューター間の構成でサンプルを実行するには、「Windows Communication Foundation Samplesの実行」の手順に従います。