Stream

W przykładzie usługi Stream pokazano użycie komunikacji w trybie transferu przesyłania strumieniowego. Usługa uwidacznia kilka operacji, które wysyłają i odbierają strumienie. Ten przykład jest hostowany samodzielnie. Zarówno klient, jak i usługa to programy konsolowe.

Uwaga

Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.

Program Windows Communication Foundation (WCF) może komunikować się w dwóch trybach transferu — buforowanych lub przesyłanych strumieniowo. W domyślnym trybie buforowanego transferu komunikat musi zostać całkowicie dostarczony, zanim odbiorca będzie mógł go odczytać. W trybie transferu przesyłania strumieniowego odbiornik może rozpocząć przetwarzanie komunikatu przed jego całkowitym dostarczeniem. Tryb przesyłania strumieniowego jest przydatny, gdy przekazywane informacje są długie i mogą być przetwarzane szeregowo. Tryb przesyłania strumieniowego jest również przydatny, gdy komunikat jest zbyt duży, aby był całkowicie buforowany.

Przesyłanie strumieniowe i kontrakty usług

Przesyłanie strumieniowe to coś, co należy wziąć pod uwagę podczas projektowania kontraktu usługi. Jeśli operacja odbiera lub zwraca duże ilości danych, należy rozważyć przesyłanie strumieniowe tych danych, aby uniknąć wysokiego wykorzystania pamięci z powodu buforowania komunikatów wejściowych lub wyjściowych. Aby przesyłać strumieniowo dane, parametr, który przechowuje dane, musi być jedynym parametrem w komunikacie. Jeśli na przykład komunikat wejściowy jest przesyłany strumieniowo, operacja musi mieć dokładnie jeden parametr wejściowy. Podobnie, jeśli komunikat wyjściowy ma być przesyłany strumieniowo, operacja musi mieć dokładnie jeden parametr wyjściowy lub wartość zwracaną. W obu przypadkach parametr lub zwracany typ wartości musi mieć Streamwartość , Messagelub IXmlSerializable. Poniżej przedstawiono kontrakt usługi używany w tym przykładzie przesyłania strumieniowego.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IStreamingSample
{
    [OperationContract]
    Stream GetStream(string data);
    [OperationContract]
    bool UploadStream(Stream stream);
    [OperationContract]
    Stream EchoStream(Stream stream);
    [OperationContract]
    Stream GetReversedStream();

}

Operacja GetStream odbiera dane wejściowe jako ciąg, który jest buforowany i zwraca Streamelement , który jest przesyłany strumieniowo. Z drugiej strony przyjmuje UploadStream wartość (przesyłaną strumieniowo Stream ) i zwraca bool wartość (buforowaną). EchoStream przyjmuje i zwraca Stream i jest przykładem operacji, której komunikaty wejściowe i wyjściowe są przesyłane strumieniowo. Na koniec nie GetReversedStream przyjmuje żadnych danych wejściowych i zwraca wartość Stream (przesyłana strumieniowo).

Włączanie strumieniowych transferów

Definiowanie kontraktów operacji zgodnie z wcześniejszym opisem zapewnia przesyłanie strumieniowe na poziomie modelu programowania. Jeśli się tam zatrzymasz, transport nadal buforuje całą zawartość komunikatu. Aby włączyć przesyłanie strumieniowe transportu, wybierz tryb transferu dla elementu powiązania transportu. Element powiązania ma TransferMode właściwość, którą można ustawić na Buffered, Streamed, StreamedRequestlub StreamedResponse. Ustawienie trybu transferu w celu Streamed włączenia komunikacji przesyłanej strumieniowo w obu kierunkach. Ustawienie trybu transferu na StreamedRequest lub StreamedResponse umożliwia komunikację strumieniową tylko w żądaniu lub odpowiedzi, odpowiednio.

Właściwość basicHttpBinding uwidacznia TransferMode w powiązaniu tak jak NetTcpBinding i NetNamedPipeBinding. W przypadku innych transportów należy utworzyć niestandardowe powiązanie, aby ustawić tryb transferu.

Poniższy kod konfiguracji z przykładu pokazuje ustawienie TransferMode właściwości na przesyłanie strumieniowe na basicHttpBinding obiekcie i niestandardowe powiązanie HTTP:

<!-- An example basicHttpBinding using streaming. -->
<basicHttpBinding>
  <binding name="HttpStreaming" maxReceivedMessageSize="67108864"
           transferMode="Streamed"/>
</basicHttpBinding>
<!-- An example customBinding using HTTP and streaming.-->
<customBinding>
  <binding name="Soap12">
    <textMessageEncoding messageVersion="Soap12WSAddressing10" />
    <httpTransport transferMode="Streamed"
                   maxReceivedMessageSize="67108864"/>
  </binding>
</customBinding>

Oprócz ustawienia na transferModeStreamedwartość , poprzedni kod konfiguracji ustawia maxReceivedMessageSize wartość 64 MB. Jako mechanizm obrony umieszcza maxReceivedMessageSize limit maksymalnego dozwolonego rozmiaru komunikatów odbieranych. Wartość domyślna maxReceivedMessageSize to 64 KB, która zwykle jest zbyt mała w przypadku scenariuszy przesyłania strumieniowego.

Przetwarzanie danych przesyłanych strumieniowo

Operacje GetStreami UploadStreamEchoStream wszystkie dotyczą wysyłania danych bezpośrednio z pliku lub zapisywania odebranych danych bezpośrednio do pliku. Jednak w niektórych przypadkach istnieje wymóg wysyłania lub odbierania dużych ilości danych i wykonywania niektórych operacji przetwarzania na fragmentach danych podczas ich wysyłania lub odbierania. Jednym ze sposobów rozwiązania takich scenariuszy jest zapisanie strumienia niestandardowego (klasy pochodzącej z Streamklasy ), która przetwarza dane podczas ich odczytu lub zapisu. Przykład GetReversedStream operacji i ReverseStream klasy.

GetReversedStream tworzy i zwraca nowe wystąpienie klasy ReverseStream. Rzeczywiste przetwarzanie odbywa się, gdy system odczytuje z tego ReverseStream obiektu. Implementacja ReverseStream.Read odczytuje fragment bajtów z pliku bazowego, odwraca je, a następnie zwraca odwrócone bajty. Nie powoduje to odwrócenia całej zawartości pliku; odwraca jeden fragment bajtów naraz. Jest to przykład pokazujący, jak można wykonać przetwarzanie strumienia, ponieważ zawartość jest odczytywana lub zapisywana z i do strumienia.

class ReverseStream : Stream
{

    FileStream inStream;
    internal ReverseStream(string filePath)
    {
        //Opens the file and places a StreamReader around it.
        inStream = File.OpenRead(filePath);
    }

    // Other methods removed for brevity.

    public override int Read(byte[] buffer, int offset, int count)
    {
        int countRead=inStream.Read(buffer, offset,count);
        ReverseBuffer(buffer, offset, countRead);
        return countRead;
    }

    public override void Close()
    {
        inStream.Close();
        base.Close();
    }
    protected override void Dispose(bool disposing)
    {
        inStream.Dispose();
        base.Dispose(disposing);
    }
    void ReverseBuffer(byte[] buffer, int offset, int count)
    {
        int i, j;
        for (i = offset, j = offset + count - 1; i < j; i++, j--)
        {
            byte currenti = buffer[i];
            buffer[i] = buffer[j];
            buffer[j] = currenti;
        }

    }
}

Uruchamianie przykładu

Aby uruchomić przykład, najpierw skompiluj usługę i klienta, postępując zgodnie z instrukcjami na końcu tego dokumentu. Następnie uruchom usługę i klienta w dwóch różnych oknach konsoli. Po uruchomieniu klienta czeka na naciśnięcie klawisza ENTER, gdy usługa będzie gotowa. Następnie klient wywołuje metody GetStream(), UploadStream() i GetReversedStream() najpierw za pośrednictwem protokołu HTTP, a następnie za pośrednictwem protokołu TCP. Oto przykładowe dane wyjściowe z usługi, a następnie przykładowe dane wyjściowe z klienta:

Dane wyjściowe usługi:

The streaming service is ready.
Press <ENTER> to terminate service.

Saving to file D:\...\uploadedfile
......................
File D:\...\uploadedfile saved
Saving to file D:\...\uploadedfile
...............
File D:\...\uploadedfile saved

Dane wyjściowe klienta:

Press <ENTER> when service is ready
------ Using HTTP ------
Calling GetStream()
Saving to file D:\...\clientfile
......................
Wrote 33405 bytes to stream

File D:\...\clientfile saved
Calling UploadStream()
Calling GetReversedStream()
Saving to file D:\...\clientfile
......................
Wrote 33405 bytes to stream

File D:\...\clientfile saved
------ Using Custom HTTP ------
Calling GetStream()
Saving to file D:\...\clientfile
...............
Wrote 33405 bytes to stream

File D:\...\clientfile saved
Calling UploadStream()
Calling GetReversedStream()
Saving to file D:\...\clientfile
...............
Wrote 33405 bytes to stream

File D:\...\clientfile saved

Press <ENTER> to terminate client.

Aby skonfigurować, skompilować i uruchomić przykład

  1. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  2. Aby skompilować wersję rozwiązania w języku C# lub Visual Basic .NET, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

  3. Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.

Uwaga

Jeśli używasz Svcutil.exe do ponownego wygenerowania konfiguracji dla tego przykładu, pamiętaj o zmodyfikowaniu nazwy punktu końcowego w konfiguracji klienta, aby był zgodny z kodem klienta.