次の方法で共有


ストリーミング フィードのサンプル

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 データを適切なサイズのセグメントで送信すると、パフォーマンスが向上します)。

サンプルを設定、ビルド、実行するには

  1. Windows Communication Foundation サンプル One-Time セットアップ手順を実行していることを確認します。

  2. ソリューションの C# または Visual Basic .NET エディションをビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。

  3. 単一または複数のコンピューター間の構成でサンプルを実行するには、「Windows Communication Foundation Samplesの実行」の手順に従います。

こちらも参照ください