Dela via


Exempel på direktuppspelningsflöden

Exemplet StreamingFeeds visar hur du hanterar syndikeringsflöden som innehåller ett stort antal objekt. På servern visar exemplet hur du fördröjer skapandet av enskilda SyndicationItem objekt i flödet tills omedelbart innan objektet skrivs till nätverksströmmen.

På klienten visar exemplet hur en anpassad syndikeringsflödesformaterare kan användas för att läsa enskilda objekt från nätverksströmmen så att feeden som läses aldrig är helt buffrad i minnet.

För att på bästa sätt demonstrera strömningsfunktionen för syndikerings-API:et använder det här exemplet ett något osannolikt scenario där servern exponerar ett flöde som innehåller ett oändligt antal objekt. I det här fallet fortsätter servern att generera nya objekt till feeden tills den fastställer att klienten har läst ett angivet antal objekt från feeden (som standard 10). För enkelhetens skull implementeras både klienten och servern i samma process och använder ett delat ItemCounter objekt för att hålla reda på hur många objekt som klienten har producerat. Typen ItemCounter finns bara i syfte att tillåta att exempelscenariot avslutas rent och är inte ett kärnelement i det mönster som demonstreras.

Demonstrationen använder Visual C#-iteratorer (med hjälp av nyckelordskonstruktionen yield return ). Mer information om iteratorer finns i avsnittet "Använda iteratorer" på MSDN.

Tjänster

Tjänsten implementerar ett grundläggande WebGetAttribute kontrakt som består av en åtgärd, enligt följande kod.

[ServiceContract]
interface IStreamingFeedService
{
    [WebGet]
    [OperationContract]
    Atom10FeedFormatter StreamedFeed();
}

Tjänsten implementerar det här kontraktet med hjälp av en ItemGenerator-klass för att skapa en potentiellt oändlig ström av SyndicationItem-instanser med hjälp av en iterator, som visas i följande kod.

class ItemGenerator
{
    public IEnumerable<SyndicationItem> GenerateItems()
    {
        while (counter.GetCount() < maxItemsRead)
        {
            itemsReturned++;
            yield return CreateNextItem();
        }

    }
    ...
}

När tjänstimplementeringen skapar feeden används utdata från ItemGenerator.GenerateItems() i stället för en buffrad samling objekt.

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();
}

Det innebär att objektströmmen aldrig är helt buffrad i minnet. Du kan observera det här beteendet genom att ange en brytpunkt för -instruktionen yield returnItemGenerator.GenerateItems() i metoden och notera att den här brytpunkten påträffas första gången efter att tjänsten har returnerat resultatet av StreamedFeed() metoden.

Klient

Klienten i det här exemplet använder en anpassad SyndicationFeedFormatter implementering som fördröjer materialiseringen av enskilda objekt i flödet i stället för att buffras till minnet. Den anpassade StreamedAtom10FeedFormatter instansen används på följande sätt.

XmlReader reader = XmlReader.Create("http://localhost:8000/Service/Feeds/StreamedFeed");
StreamedAtom10FeedFormatter formatter = new StreamedAtom10FeedFormatter(counter);

SyndicationFeed feed = formatter.ReadFrom(reader);

Normalt returneras inte ett anrop till ReadFrom(XmlReader) förrän hela innehållet i flödet har lästs från nätverket och buffrats till minnet. Objektet StreamedAtom10FeedFormatter åsidosätter ReadItems(XmlReader, SyndicationFeed, Boolean) och returnerar en iterator i stället för en buffrad samling, enligt följande kod.

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();
}

Därför läss inte varje objekt från nätverket förrän klientprogrammet som passerar resultatet av ReadItems() är redo att använda det. Du kan observera det här beteendet genom att ange en brytpunkt på instruktionen yield return inuti StreamedAtom10FeedFormatter.DelayReadItems() och notera att den här brytpunkten påträffas för första gången efter att anropet till ReadFrom() har slutförts.

Följande instruktioner visar hur du skapar och kör exemplet. Observera att även om servern slutar generera objekt efter att klienten har läst 10 objekt, visar utdata att klienten läser betydligt fler än 10 objekt. Detta beror på att nätverksbindningen som används av exemplet överför data i segment på fyra kilobyte (KB). Därför tar klienten emot 4 KB objektdata innan den har möjlighet att läsa ett objekt. Det här är ett normalt beteende (att skicka strömmade HTTP-data i segment av rimlig storlek ökar prestandan).

Så här konfigurerar du, skapar och kör exemplet

  1. Kontrollera att du har utfört One-Time installationsproceduren för Windows Communication Foundation-exempel.

  2. Om du vill skapa C# eller Visual Basic .NET-versionen av lösningen följer du anvisningarna i Skapa Windows Communication Foundation-exempel.

  3. Om du vill köra exemplet i en konfiguration med en eller flera datorer följer du anvisningarna i Köra Windows Communication Foundation-exempel.

Se även