Voorbeeld van streamingfeeds
Het StreamingFeeds-voorbeeld laat zien hoe u syndicatiefeeds beheert die grote aantallen items bevatten. Op de server laat het voorbeeld zien hoe u het maken van afzonderlijke SyndicationItem objecten in de feed kunt vertragen totdat het item naar de netwerkstroom wordt geschreven.
Op de client laat het voorbeeld zien hoe een aangepaste syndicatiefeedindeling kan worden gebruikt om afzonderlijke items uit de netwerkstroom te lezen, zodat de feed die wordt gelezen nooit volledig in het geheugen wordt gebufferd.
Om het beste de streaming-mogelijkheid van de syndicatie-API te demonstreren, maakt dit voorbeeld gebruik van een enigszins onwaarschijnlijk scenario waarin de server een feed weergeeft die een oneindig aantal items bevat. In dit geval blijft de server nieuwe items genereren in de feed totdat wordt vastgesteld dat de client een opgegeven aantal items uit de feed heeft gelezen (standaard 10). Ter vereenvoudiging worden zowel de client als de server in hetzelfde proces geïmplementeerd en wordt een gedeeld ItemCounter
object gebruikt om bij te houden hoeveel items de client heeft geproduceerd. Het ItemCounter
type bestaat alleen om het voorbeeldscenario op schone wijze te laten beëindigen en is geen kernelement van het patroon dat wordt gedemonstreerd.
De demonstratie maakt gebruik van Visual C#-iterators (met behulp van de yield return
trefwoordconstructie). Zie het onderwerp Iterators gebruiken op MSDN voor meer informatie over iterators.
Service
De service implementeert een basiscontract WebGetAttribute dat uit één bewerking bestaat, zoals wordt weergegeven in de volgende code.
[ServiceContract]
interface IStreamingFeedService
{
[WebGet]
[OperationContract]
Atom10FeedFormatter StreamedFeed();
}
De service implementeert dit contract met behulp van een ItemGenerator
klasse om een potentieel oneindige stroom exemplaren te maken met behulp van SyndicationItem een iterator, zoals wordt weergegeven in de volgende code.
class ItemGenerator
{
public IEnumerable<SyndicationItem> GenerateItems()
{
while (counter.GetCount() < maxItemsRead)
{
itemsReturned++;
yield return CreateNextItem();
}
}
...
}
Wanneer de service-implementatie de feed maakt, wordt de uitvoer ItemGenerator.GenerateItems()
gebruikt in plaats van een gebufferde verzameling items.
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();
}
Hierdoor wordt de itemstroom nooit volledig in het geheugen gebufferd. U kunt dit gedrag observeren door een onderbrekingspunt in te stellen op de yield return
instructie in de ItemGenerator.GenerateItems()
methode en te noteren dat dit onderbrekingspunt voor het eerst wordt aangetroffen nadat de service het resultaat van de StreamedFeed()
methode heeft geretourneerd.
Klant
De client in dit voorbeeld maakt gebruik van een aangepaste SyndicationFeedFormatter implementatie die de materialisatie van afzonderlijke items in de feed vertraagt in plaats van ze in het geheugen te bufferen. Het aangepaste StreamedAtom10FeedFormatter
exemplaar wordt als volgt gebruikt.
XmlReader reader = XmlReader.Create("http://localhost:8000/Service/Feeds/StreamedFeed");
StreamedAtom10FeedFormatter formatter = new StreamedAtom10FeedFormatter(counter);
SyndicationFeed feed = formatter.ReadFrom(reader);
Normaal gesproken retourneert een aanroep niet ReadFrom(XmlReader) totdat de volledige inhoud van de feed is gelezen uit het netwerk en in het geheugen is gebufferd. Het StreamedAtom10FeedFormatter
object overschrijft ReadItems(XmlReader, SyndicationFeed, Boolean) echter om een iterator te retourneren in plaats van een gebufferde verzameling, zoals wordt weergegeven in de volgende code.
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();
}
Als gevolg hiervan wordt elk item pas gelezen uit het netwerk als de clienttoepassing die de resultaten ReadItems()
doorkruist, klaar is om het te gebruiken. U kunt dit gedrag observeren door een onderbrekingspunt in te stellen op de instructie in de yield return
instructie en StreamedAtom10FeedFormatter.DelayReadItems()
te zien dat dit onderbrekingspunt voor het eerst wordt aangetroffen nadat de aanroep is ReadFrom()
voltooid.
De volgende instructies laten zien hoe u het voorbeeld bouwt en uitvoert. Hoewel de server stopt met het genereren van items nadat de client 10 items heeft gelezen, toont de uitvoer aan dat de client aanzienlijk meer dan 10 items leest. Dit komt doordat de netwerkbinding die door het voorbeeld wordt gebruikt, gegevens verzendt in segmenten van vier kilobyte (KB). Als zodanig ontvangt de client 4 KB aan itemgegevens voordat deze de mogelijkheid heeft om zelfs één item te lezen. Dit is normaal gedrag (het verzenden van gestreamde HTTP-gegevens in segmenten van redelijk formaat verhoogt de prestaties).
Het voorbeeld instellen, compileren en uitvoeren
Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.
Als u de C# of Visual Basic .NET-editie van de oplossing wilt bouwen, volgt u de instructies in het bouwen van de Windows Communication Foundation-voorbeelden.
Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.