Partilhar via


Exemplo de feeds de streaming

O exemplo StreamingFeeds demonstra como gerenciar feeds de distribuição que contêm um grande número de itens. No servidor, o exemplo demonstra como atrasar a criação de objetos individuais SyndicationItem dentro do feed até imediatamente antes que o item seja gravado no fluxo de rede.

No cliente, o exemplo mostra como um formatador de feed de distribuição personalizado pode ser usado para ler itens individuais do fluxo de rede para que o feed que está sendo lido nunca seja totalmente armazenado em buffer na memória.

Para demonstrar melhor a capacidade de streaming da API de distribuição, este exemplo usa um cenário um tanto improvável no qual o servidor expõe um feed que contém um número infinito de itens. Nesse caso, o servidor continua gerando novos itens no feed até determinar que o cliente leu um número especificado de itens do feed (por padrão, 10). Para simplificar, o cliente e o servidor são implementados no mesmo processo e usam um objeto compartilhado ItemCounter para controlar quantos itens o cliente produziu. O ItemCounter tipo existe apenas com a finalidade de permitir que o cenário de amostra termine de forma limpa e não é um elemento central do padrão que está sendo demonstrado.

A demonstração faz uso de iteradores Visual C# (usando a construção de yield return palavra-chave). Para obter mais informações sobre iteradores, consulte o tópico "Usando iteradores" no MSDN.

Serviço

O serviço implementa um contrato básico WebGetAttribute que consiste em uma operação, conforme mostrado no código a seguir.

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

O serviço implementa esse contrato usando uma ItemGenerator classe para criar um fluxo potencialmente infinito de SyndicationItem instâncias usando um iterador, conforme mostrado no código a seguir.

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

    }
    ...
}

Quando a implementação do serviço cria o feed, a saída do ItemGenerator.GenerateItems() é usada em vez de uma coleção de itens em buffer.

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

Como resultado, o fluxo de itens nunca é totalmente armazenado em buffer na memória. Você pode observar esse comportamento definindo um ponto de interrupção na yield return instrução dentro do método e observando que esse ponto de ItemGenerator.GenerateItems() interrupção é encontrado pela primeira vez depois que o serviço retornou o resultado do StreamedFeed() método.

Cliente

O cliente neste exemplo usa uma implementação personalizada SyndicationFeedFormatter que atrasa a materialização de itens individuais no feed em vez de armazená-los em buffer na memória. A instância personalizada StreamedAtom10FeedFormatter é usada da seguinte maneira.

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

SyndicationFeed feed = formatter.ReadFrom(reader);

Normalmente, uma chamada para ReadFrom(XmlReader) não retorna até que todo o conteúdo do feed tenha sido lido da rede e armazenado em buffer na memória. No entanto, o StreamedAtom10FeedFormatter objeto substitui ReadItems(XmlReader, SyndicationFeed, Boolean) para retornar um iterador em vez de uma coleção em buffer, conforme mostrado no código a seguir.

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

Como resultado, cada item não é lido da rede até que o aplicativo cliente que atravessa os resultados esteja ReadItems() pronto para usá-lo. Você pode observar esse comportamento definindo um ponto de interrupção na yield return instrução dentro de e percebendo que esse ponto de interrupção é encontrado pela primeira vez após a conclusão da StreamedAtom10FeedFormatter.DelayReadItems() chamada ReadFrom() .

As instruções a seguir mostram como criar e executar o exemplo. Observe que, embora o servidor pare de gerar itens depois que o cliente leu 10 itens, a saída mostra que o cliente lê significativamente mais de 10 itens. Isso ocorre porque a ligação de rede usada pelo exemplo transmite dados em segmentos de quatro kilobytes (KB). Como tal, o cliente recebe 4KB de dados do item antes de ter a oportunidade de ler até mesmo um item. Este é um comportamento normal (enviar dados HTTP transmitidos em segmentos de tamanho razoável aumenta o desempenho).

Para configurar, compilar e executar o exemplo

  1. Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para criar a edição C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.

  3. Para executar o exemplo em uma configuração de máquina única ou cruzada, siga as instruções em Executando os exemplos do Windows Communication Foundation.

Consulte também