Duże ilości danych i przesyłanie strumieniowe

Windows Communication Foundation (WCF) to infrastruktura komunikacji oparta na formacie XML. Ponieważ dane XML są często kodowane w standardowym formacie tekstowym zdefiniowanym w specyfikacji XML 1.0, deweloperzy połączonych systemów i architekci zwykle są zaniepokojeni śladem przewodu (lub rozmiarem) komunikatów wysyłanych przez sieć, a kodowanie tekstowe XML stanowi szczególne wyzwania dla wydajnego transferu danych binarnych.

Podstawowe zagadnienia

Aby podać podstawowe informacje na temat poniższych informacji dotyczących programu WCF, w tej sekcji opisano pewne ogólne problemy i zagadnienia dotyczące kodowania, danych binarnych i przesyłania strumieniowego, które są zwykle stosowane do infrastruktury połączonych systemów.

Dane kodowania: tekst a binarny

Często wyrażane obawy deweloperów obejmują postrzeganie, że kod XML ma znaczne obciążenie w porównaniu z formatami binarnymi ze względu na powtarzalny charakter tagów początkowych i tagów końcowych, że kodowanie wartości liczbowych jest uważane za znacznie większe, ponieważ są one wyrażone w wartościach tekstowych, i że dane binarne nie mogą być skutecznie wyrażane, ponieważ muszą być specjalnie zakodowane do osadzania w formacie tekstowym.

Chociaż wiele z tych i podobnych problemów jest prawidłowych, rzeczywista różnica między komunikatami zakodowanymi tekstem XML w środowisku usług sieci Web XML i komunikatami zakodowanymi binarnie w starszym środowisku zdalnego wywołania procedury (RPC) jest często znacznie mniej znacząca niż w początkowej kwestii.

Podczas gdy komunikaty zakodowane w formacie XML są przezroczyste i "czytelne dla człowieka", komunikaty binarne są często dość niejasne w porównaniu i trudne do dekodowania bez narzędzi. Ta różnica w czytelności prowadzi do przeoczenia, że komunikaty binarne również często niosą metadane wbudowane w ładunku, co dodaje obciążenie tak samo jak w przypadku komunikatów tekstowych XML. Dotyczy to w szczególności formatów binarnych, które mają na celu zapewnienie możliwości luźnego sprzężenia i dynamicznego wywołania.

Jednak formaty binarne często zawierają takie opisowe informacje o metadanych w "nagłówku", który deklaruje również układ danych dla następujących rekordów danych. Ładunek jest następnie zgodny z tą wspólną deklaracją bloku metadanych z minimalnym obciążeniem. Z kolei kod XML otacza każdy element danych w elemencie lub atrybucie, tak aby otaczające metadane były powtarzanie uwzględniane dla każdego obiektu ładunku serializowanego. W związku z tym rozmiar pojedynczego zserializowanego obiektu ładunku jest podobny podczas porównywania tekstu z reprezentacjami binarnymi, ponieważ niektóre metadane opisowe muszą być wyrażone dla obu tych elementów, ale format binarny korzysta z opisu współużytkowanego metadanych z każdym dodatkowym obiektem ładunku, który jest transferowany z powodu niższego ogólnego obciążenia.

Mimo to w przypadku niektórych typów danych, takich jak liczby, może wystąpić wada użycia stałych, binarnych reprezentacji liczbowych, takich jak 128-bitowy typ dziesiętny zamiast zwykłego tekstu, ponieważ reprezentacja zwykłego tekstu może być mniejsza o kilka bajtów. Dane tekstowe mogą również mieć zalety rozmiaru z typowo bardziej elastycznych opcji kodowania tekstu XML, podczas gdy niektóre formaty binarne mogą domyślnie mieć format 16-bitowy lub nawet 32-bitowy Unicode, który nie ma zastosowania do formatu XML binarnego platformy .NET.

W rezultacie podjęcie decyzji między tekstem lub plikiem binarnym nie jest tak proste, jak przy założeniu, że komunikaty binarne są zawsze mniejsze niż komunikaty TEKSTOWE XML.

Wyraźną zaletą komunikatów TEKSTowych XML jest to, że są one oparte na standardach i oferują najszerszy wybór opcji współdziałania i obsługi platformy. Aby uzyskać więcej informacji, zobacz sekcję "Kodowanie" w dalszej części tego tematu.

Zawartość binarna

Jeden obszar, w którym kodowanie binarne jest lepsze od kodowań opartych na tekście pod względem wynikowego rozmiaru komunikatu, to duże binarne elementy danych, takie jak obrazy, filmy wideo, klipy dźwiękowe lub dowolna inna forma nieprzezroczystych danych binarnych, które muszą być wymieniane między usługami a ich użytkownikami. Aby dopasować te typy danych do tekstu XML, typowym podejściem jest kodowanie ich przy użyciu kodowania Base64.

W ciągu zakodowanym w formacie Base64 każdy znak reprezentuje 6-bitowe oryginalne dane 8-bitowe, co powoduje, że współczynnik 4:3 kodowania dla base64 nie liczy dodatkowych znaków formatowania (karetki powrotu/wiersza), które są często dodawane zgodnie z konwencją. Chociaż znaczenie różnic między kodowaniem XML i binarnym zwykle zależy od scenariusza, przyrost rozmiaru przekraczający 33% podczas przesyłania ładunku 500 MB jest zwykle nie do przyjęcia.

Aby uniknąć tego obciążenia kodowania, standard mechanizmu optymalizacji transmisji komunikatów (MTOM) pozwala na zewnętrznie duże elementy danych, które są zawarte w komunikacie i niosąc je z komunikatem jako dane binarne bez żadnego specjalnego kodowania. Dzięki funkcji MTOM wiadomości są wymieniane w podobny sposób do wiadomości e-mail protokołu SIMPLE Mail Transfer Protocol (SMTP) z załącznikami lub osadzoną zawartością (obrazy i inną osadzoną zawartością); Komunikaty MTOM są pakowane jako sekwencje wieloczęściowe/powiązane z programem MIME z częścią główną będącą rzeczywistym komunikatem PROTOKOŁU SOAP.

Komunikat PROTOKOŁU MTOM SOAP jest modyfikowany z jego niekodowanej wersji, tak aby specjalne tagi elementów odwołujące się do odpowiednich części MIME znajdowały się w oryginalnej wiadomości zawierającej dane binarne. W związku z tym komunikat SOAP odwołuje się do zawartości binarnej, wskazując na wysłane z nim części MIME, ale w przeciwnym razie po prostu przenosi dane tekstowe XML. Ponieważ ten model jest ściśle zgodny z dobrze ugruntowanym modelem SMTP, istnieje szeroka obsługa narzędzi do kodowania i dekodowania komunikatów MTOM na wielu platformach, co sprawia, że jest to niezwykle współdziałanie.

Mimo to, podobnie jak w przypadku modelu Base64, mtOM ma również pewne niezbędne obciążenie dla formatu MIME, dzięki czemu zalety korzystania z modelu MTOM są widoczne tylko wtedy, gdy rozmiar elementu danych binarnych przekracza około 1 KB. Ze względu na obciążenie komunikaty zakodowane w formacie MTOM mogą być większe niż komunikaty używające kodowania Base64 dla danych binarnych, jeśli ładunek binarny pozostaje poniżej tego progu. Aby uzyskać więcej informacji, zobacz sekcję "Kodowanie" w dalszej części tego tematu.

Zawartość dużych danych

Odłożenie przewodu, wcześniej wspomniany 500 MB ładunku stanowi również wielkie wyzwanie lokalne dla usługi i klienta. Domyślnie program WCF przetwarza komunikaty w trybie buforowym. Oznacza to, że cała zawartość komunikatu jest obecna w pamięci, zanim zostanie wysłana lub po jej odebraniu. Chociaż jest to dobra strategia dla większości scenariuszy i niezbędna do obsługi komunikatów, takich jak podpisy cyfrowe i niezawodne dostarczanie, duże komunikaty mogą wyczerpać zasoby systemu.

Strategia do obsługi dużych ładunków to przesyłanie strumieniowe. Podczas gdy komunikaty, zwłaszcza te wyrażone w formacie XML, są powszechnie uważane za stosunkowo kompaktowe pakiety danych, komunikat może mieć wiele gigabajtów rozmiaru i przypomina ciągły strumień danych więcej niż pakiet danych. Gdy dane są przesyłane w trybie przesyłania strumieniowego zamiast trybu buforowanego, nadawca udostępnia zawartość treści wiadomości odbiorcy w postaci strumienia, a infrastruktura komunikatów stale przekazuje dane od nadawcy do odbiorcy, gdy stanie się dostępna.

Najbardziej typowym scenariuszem, w którym występują takie duże transfery zawartości danych, są transfery binarnych obiektów danych, które:

  • Nie można łatwo podzielić na sekwencję komunikatów.

  • Należy dostarczyć w odpowiednim czasie.

  • Nie są dostępne w całości podczas inicjowania transferu.

W przypadku danych, które nie mają tych ograniczeń, zazwyczaj lepiej jest wysyłać sekwencje komunikatów w zakresie sesji niż jeden duży komunikat. Aby uzyskać więcej informacji, zobacz sekcję "Dane przesyłane strumieniowo" w dalszej części tego tematu.

Podczas wysyłania dużych ilości danych należy ustawić maxAllowedContentLength ustawienie usług IIS (aby uzyskać więcej informacji, zobacz Konfigurowanie limitów żądań usług IIS) i maxReceivedMessageSize ustawienie powiązania (na przykład System.ServiceModel.BasicHttpBinding.MaxReceivedMessageSize lub MaxReceivedMessageSize). Właściwość maxAllowedContentLength jest domyślnie ustawiona na 28,6 MB, a maxReceivedMessageSize właściwość jest domyślnie ustawiona na 64 KB.

Kodowanie

Kodowanie definiuje zestaw reguł dotyczących sposobu prezentowania komunikatów w sieci. Koder implementuje takie kodowanie i jest odpowiedzialny po stronie nadawcy za przekształcenie w pamięć Message strumienia bajtów lub buforu bajtów, który można wysłać przez sieć. Po stronie odbiorcy koder zamienia sekwencję bajtów w komunikat w pamięci.

Program WCF zawiera trzy kodery i umożliwia pisanie i podłączenie własnych koderów w razie potrzeby.

Każde ze standardowych powiązań zawiera wstępnie skonfigurowany koder, w którym powiązania z prefiksem Net* używają kodera binarnego (włącznie BinaryMessageEncodingBindingElement z klasą), podczas gdy BasicHttpBinding klasy i WSHttpBinding domyślnie używają kodera komunikatów tekstowych (za pomocą TextMessageEncodingBindingElement klasy).

Element powiązania kodera opis
TextMessageEncodingBindingElement Koder komunikatów tekstowych jest domyślnym koderem dla wszystkich powiązań opartych na protokole HTTP i odpowiednim wyborem dla wszystkich powiązań niestandardowych, w których współdziałanie jest najwyższym problemem. Ten koder odczytuje i zapisuje standardowe komunikaty tekstowe PROTOKOŁU SOAP 1.1/SOAP 1.2 bez specjalnej obsługi danych binarnych. System.ServiceModel.Channels.MessageVersion Jeśli właściwość komunikatu jest ustawiona na MessageVersion.Nonewartość , otoka koperty PROTOKOŁU SOAP zostanie pominięta z danych wyjściowych, a tylko zawartość treści komunikatu jest serializowana.
MtomMessageEncodingBindingElement Koder komunikatów MTOM to koder tekstowy, który implementuje specjalną obsługę danych binarnych i nie jest używany domyślnie w żadnym ze standardowych powiązań, ponieważ jest to ściśle narzędzie optymalizacji wielkości liter. Jeśli komunikat zawiera dane binarne, które przekraczają próg, w którym kodowanie MTOM daje korzyść, dane są zewnętrzne w części MIME po kopercie komunikatu. Zobacz Włączanie funkcji MTOM w dalszej części tej sekcji.
BinaryMessageEncodingBindingElement Koder komunikatów binarnych jest domyślnym koderem powiązań Net* i odpowiednim wyborem za każdym razem, gdy obie komunikujące się strony są oparte na WCF. Koder komunikatów binarnych używa formatu XML binarnego platformy .NET, reprezentacji binarnej specyficznej dla firmy Microsoft dla zestawów informacji XML (Infosets), która zazwyczaj daje mniejszy ślad niż równoważna reprezentacja XML 1.0 i koduje dane binarne jako strumień bajtów.

Kodowanie komunikatów tekstowych jest zazwyczaj najlepszym wyborem dla każdej ścieżki komunikacyjnej, która wymaga współdziałania, podczas gdy kodowanie komunikatów binarnych jest najlepszym wyborem dla każdej innej ścieżki komunikacji. Kodowanie komunikatów binarnych zwykle daje mniejsze rozmiary komunikatów w porównaniu z tekstem pojedynczego komunikatu i stopniowo nawet mniejsze rozmiary komunikatów w czasie trwania sesji komunikacji. W przeciwieństwie do kodowania tekstu kodowanie binarne nie musi używać specjalnej obsługi danych binarnych, takich jak używanie base64, ale reprezentuje bajty jako bajty.

Jeśli rozwiązanie nie wymaga współdziałania, ale nadal chcesz używać transportu HTTP, możesz utworzyć BinaryMessageEncodingBindingElement powiązanie niestandardowe używające HttpTransportBindingElement klasy transportu. Jeśli wielu klientów w usłudze wymaga współdziałania, zaleca się uwidocznienie równoległych punktów końcowych, dla których każdy ma odpowiednie opcje transportu i kodowania dla odpowiednich klientów.

Włączanie modelu MTOM

Gdy współdziałanie jest wymagane, a duże dane binarne muszą być wysyłane, kodowanie komunikatów MTOM jest alternatywną strategią kodowania, którą można włączyć w standardzie BasicHttpBinding lub powiązaniach, ustawiając odpowiednią MessageEncoding właściwość na Mtom lub tworząc MtomMessageEncodingBindingElement element w obiekcie CustomBindingWSHttpBinding . Poniższy przykładowy kod wyodrębniony z przykładu kodowania MTOM pokazuje sposób włączania funkcji MTOM w konfiguracji.

<system.serviceModel>  
     …  
    <bindings>  
      <wsHttpBinding>  
        <binding name="ExampleBinding" messageEncoding="Mtom"/>  
      </wsHttpBinding>  
    </bindings>  
     …  
</system.serviceModel>  

Jak wspomniano wcześniej, decyzja o użyciu kodowania MTOM zależy od wysyłanego woluminu danych. Ponadto, ponieważ funkcja MTOM jest włączona na poziomie powiązania, włączenie funkcji MTOM wpływa na wszystkie operacje w danym punkcie końcowym.

Ponieważ koder MTOM zawsze emituje zakodowany w formacie MTOM komunikat MIME/wieloczęściowy, niezależnie od tego, czy dane binarne kończą się zewnętrznie, zazwyczaj należy włączyć tylko mtOM dla punktów końcowych, które wymieniają komunikaty z ponad 1 KB danych binarnych. Ponadto kontrakty usług przeznaczone do użytku z punktami końcowymi z włączoną funkcją MTOM powinny być ograniczone do określania takich operacji transferu danych. Powiązane funkcje sterowania powinny znajdować się w osobnym kontrakcie. Ta reguła "tylko mtOM" ma zastosowanie tylko do komunikatów wysyłanych za pośrednictwem punktu końcowego z włączoną usługą MTOM; Koder MTOM może również dekodować i analizować przychodzące komunikaty inne niż MTOM.

Korzystanie z kodera MTOM jest zgodne ze wszystkimi innymi funkcjami WCF. Należy pamiętać, że może nie być możliwe obserwowanie tej reguły we wszystkich przypadkach, na przykład gdy wymagana jest obsługa sesji.

Model programowania

Niezależnie od tego, które z trzech wbudowanych koderów używanych w aplikacji, środowisko programowania jest identyczne w odniesieniu do przesyłania danych binarnych. Różnica polega na tym, jak usługa WCF obsługuje dane na podstawie ich typów danych.

[DataContract]  
class MyData  
{  
    [DataMember]  
    byte[] binaryBuffer;  
    [DataMember]  
    string someStringData;  
}

W przypadku korzystania z modelu MTOM poprzedni kontrakt danych jest serializowany zgodnie z następującymi regułami:

  • Jeśli binaryBuffer nie null jest i indywidualnie zawiera wystarczające dane, aby uzasadnić obciążenie zewnętrzne MTOM (nagłówki MIME itd.) w porównaniu z kodowaniem Base64, dane są zewnętrznie i przenoszone z komunikatem jako binarną częścią MIME. Jeśli próg nie zostanie przekroczony, dane są kodowane jako Base64.

  • Ciąg (i wszystkie inne typy, które nie są binarne) są zawsze reprezentowane jako ciąg wewnątrz treści komunikatu, niezależnie od rozmiaru.

Wpływ na kodowanie MTOM jest taki sam, czy używasz jawnego kontraktu danych, jak pokazano w poprzednim przykładzie, użyj listy parametrów w operacji, zagnieżdżonych kontraktów danych lub transferu obiektu kontraktu danych wewnątrz kolekcji. Tablice bajtów są zawsze kandydatami do optymalizacji i są optymalizowane, jeśli progi optymalizacji są spełnione.

Uwaga

Nie należy używać System.IO.Stream typów pochodnych wewnątrz kontraktów danych. Dane strumienia powinny być przekazywane przy użyciu modelu przesyłania strumieniowego, co wyjaśniono w poniższej sekcji "Dane przesyłane strumieniowo".

Przesyłanie strumieniowe danych

Jeśli masz dużą ilość danych do transferu, tryb przesyłania strumieniowego w programie WCF jest wykonalną alternatywą dla domyślnego zachowania buforowania i przetwarzania komunikatów w pamięci w całości.

Jak wspomniano wcześniej, włącz przesyłanie strumieniowe tylko dla dużych wiadomości (z zawartością tekstową lub binarną), jeśli nie można segmentować danych, jeśli komunikat musi być dostarczany w odpowiednim czasie lub jeśli dane nie są jeszcze w pełni dostępne po zainicjowaniu transferu.

Ograniczenia

W przypadku włączenia przesyłania strumieniowego nie można użyć znacznej liczby funkcji programu WCF:

  • Nie można wykonać podpisów cyfrowych treści wiadomości, ponieważ wymagają one obliczenia skrótu dla całej zawartości wiadomości. W przypadku przesyłania strumieniowego zawartość nie jest w pełni dostępna, gdy nagłówki wiadomości są konstruowane i wysyłane, dlatego nie można obliczyć podpisu cyfrowego.

  • Szyfrowanie zależy od podpisów cyfrowych w celu sprawdzenia, czy dane zostały prawidłowo zrekonstruowane.

  • Niezawodne sesje muszą buforować wysłane komunikaty na kliencie w celu ponownego uzyskania informacji, jeśli komunikat zostanie utracony w transferze i musi przechowywać komunikaty w usłudze przed przekazaniem ich do implementacji usługi w celu zachowania kolejności komunikatów w przypadku odebrania komunikatów poza sekwencją.

Ze względu na te ograniczenia funkcjonalne można używać tylko opcji zabezpieczeń na poziomie transportu do przesyłania strumieniowego i nie można włączyć niezawodnych sesji. Przesyłanie strumieniowe jest dostępne tylko z następującymi powiązaniami zdefiniowanymi przez system:

Ponieważ podstawowe transporty NetTcpBinding i NetNamedPipeBinding mają nieodłączną niezawodną obsługę dostarczania i sesji opartej na połączeniach, w przeciwieństwie do protokołu HTTP, te dwa powiązania mają minimalny wpływ tylko na te ograniczenia, w praktyce.

Przesyłanie strumieniowe nie jest dostępne w przypadku transportu kolejkowania komunikatów (MSMQ, Message Queuing) i dlatego nie można jej używać z klasą NetMsmqBinding lub MsmqIntegrationBinding . Transport kolejkowania komunikatów obsługuje tylko buforowane transfery danych z ograniczonym rozmiarem komunikatu, podczas gdy wszystkie inne transporty nie mają żadnego praktycznego limitu rozmiaru komunikatów dla zdecydowanej większości scenariuszy.

Przesyłanie strumieniowe nie jest również dostępne w przypadku korzystania z transportu kanału równorzędnego, więc nie jest dostępne w programie NetPeerTcpBinding.

Przesyłanie strumieniowe i sesje

Podczas przesyłania strumieniowego wywołań z powiązaniem opartym na sesji może wystąpić nieoczekiwane zachowanie. Wszystkie wywołania przesyłania strumieniowego są wykonywane za pośrednictwem jednego kanału (kanału datagramu), który nie obsługuje sesji, nawet jeśli używane powiązanie jest skonfigurowane do używania sesji. Jeśli wielu klientów wykonuje wywołania przesyłania strumieniowego do tego samego obiektu usługi za pośrednictwem powiązania opartego na sesji, a tryb współbieżności obiektu usługi jest ustawiony na pojedynczy, a jego tryb kontekstu wystąpienia jest ustawiony na PerSession, wszystkie wywołania muszą przechodzić przez kanał datagramu i dlatego tylko jedno wywołanie jest przetwarzane w danym momencie. Jeden lub więcej klientów może wtedy upłynął limit czasu. Ten problem można obejść, ustawiając tryb kontekstu wystąpienia obiektu usługi na PerCall lub współbieżność na wiele.

Uwaga

MaxConcurrentSessions nie ma wpływu w tym przypadku, ponieważ jest dostępna tylko jedna "sesja".

Włączanie przesyłania strumieniowego

Przesyłanie strumieniowe można włączyć na następujące sposoby:

  • Wysyłanie i akceptowanie żądań w trybie przesyłania strumieniowego oraz akceptowanie i zwracanie odpowiedzi w trybie buforowym (StreamedRequest).

  • Wysyłanie i akceptowanie żądań w trybie buforowym oraz akceptowanie i zwracanie odpowiedzi w trybie strumieniowym (StreamedResponse).

  • Wysyłanie i odbieranie żądań i odpowiedzi w trybie strumieniowym w obu kierunkach. (Streamed).

Przesyłanie strumieniowe można wyłączyć, ustawiając tryb transferu na Bufferedwartość , która jest ustawieniem domyślnym dla wszystkich powiązań. Poniższy kod pokazuje, jak ustawić tryb transferu w konfiguracji.

<system.serviceModel>  
     …  
    <bindings>  
      <basicHttpBinding>  
        <binding name="ExampleBinding" transferMode="Streamed"/>  
      </basicHttpBinding>  
    </bindings>  
     …  
</system.serviceModel>  

Podczas tworzenia wystąpienia powiązania w kodzie należy ustawić odpowiednią TransferMode właściwość powiązania (lub elementu powiązania transportu, jeśli tworzysz powiązanie niestandardowe) na jedną z wcześniej wymienionych wartości.

Możesz włączyć przesyłanie strumieniowe dla żądań i odpowiedzi lub dla obu kierunków niezależnie po obu stronach komunikujących się stron bez wpływu na funkcjonalność. Należy jednak zawsze zakładać, że transferowany rozmiar danych jest tak znaczący, że włączenie przesyłania strumieniowego jest uzasadnione w obu punktach końcowych łącza komunikacyjnego. W przypadku komunikacji międzyplatformowej, w której jeden z punktów końcowych nie jest implementowany za pomocą usługi WCF, możliwość korzystania z przesyłania strumieniowego zależy od możliwości przesyłania strumieniowego platformy. Innym rzadkim wyjątkiem może być scenariusz oparty na użyciu pamięci, w którym klient lub usługa musi zminimalizować jego zestaw roboczy i może sobie pozwolić tylko na małe rozmiary buforów.

Włączanie przesyłania strumieniowego asynchronicznego

Aby włączyć przesyłanie strumieniowe asynchroniczne, dodaj DispatcherSynchronizationBehavior zachowanie punktu końcowego do hosta usługi i ustaw jego AsynchronousSendEnabled właściwość na true. Dodaliśmy również możliwość rzeczywistego asynchronicznego przesyłania strumieniowego po stronie wysyłania. Zwiększa to skalowalność usługi w scenariuszach, w których komunikaty przesyłane strumieniowo do wielu klientów, z których niektóre są powolne w odczytywaniu, prawdopodobnie z powodu przeciążenia sieci lub w ogóle nie odczytują. W tych scenariuszach nie blokujemy pojedynczych wątków w usłudze na klienta. Dzięki temu usługa może przetwarzać wielu innych klientów, co zwiększa skalowalność usługi.

Model programowania dla przesyłanych strumieniowo

Model programowania do przesyłania strumieniowego jest prosty. W przypadku odbierania danych przesyłanych strumieniowo określ kontrakt operacji, który ma jeden Stream typdowy parametr wejściowy. W przypadku zwracania strumieniowych danych zwróć Stream odwołanie.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]  
public interface IStreamedService  
{  
    [OperationContract]  
    Stream Echo(Stream data);  
    [OperationContract]  
    Stream RequestInfo(string query);  
    [OperationContract(OneWay=true)]  
    void ProvideInfo(Stream data);  
}  

Operacja Echo w poprzednim przykładzie odbiera i zwraca strumień i dlatego powinna być używana w powiązaniu z elementem Streamed. W przypadku operacji RequestInfoStreamedResponse najlepiej nadaje się, ponieważ zwraca tylko wartość Stream. Operacja jednokierunkowa najlepiej nadaje się do obsługi StreamedRequest.

Należy pamiętać, że dodanie drugiego parametru do następujących Echo operacji lub ProvideInfo powoduje przywrócenie modelu usługi do strategii buforowanej i użycie reprezentacji serializacji w czasie wykonywania strumienia. Tylko operacje z pojedynczym parametrem strumienia wejściowego są zgodne z przesyłaniem strumieniowym żądań end-to-end.

Ta reguła jest podobnie stosowana do kontraktów komunikatów. Jak pokazano w poniższym kontrakcie komunikatów, możesz mieć tylko jeden element członkowski treści w kontrakcie komunikatów, który jest strumieniem. Jeśli chcesz przekazać dodatkowe informacje strumieniowi, te informacje muszą być przenoszone w nagłówkach komunikatów. Treść wiadomości jest zarezerwowana wyłącznie dla zawartości strumienia.

[MessageContract]  
public class UploadStreamMessage  
{  
   [MessageHeader]  
   public string appRef;  
   [MessageBodyMember]  
   public Stream data;  
}

Przesyłanie strumieniowe kończy się i komunikat jest zamykany, gdy strumień osiągnie koniec pliku (EOF). Podczas wysyłania komunikatu (zwracania wartości lub wywoływania operacji) można przekazać FileStream element i infrastruktury WCF następnie ściągnąć wszystkie dane z tego strumienia do momentu całkowitego odczytania i osiągnięcia EOF strumienia. Aby przesłać strumieniowo dane dla źródła, którego nie ma takiej wstępnie utworzonej Stream klasy pochodnej, skonstruuj taką klasę, nakładaj na źródło strumienia i użyj tej klasy jako argumentu lub wartości zwracanej.

Podczas odbierania komunikatu usługa WCF konstruuje strumień za pośrednictwem zawartości treści komunikatu zakodowanej w formacie Base64 (lub odpowiedniej części MIME, jeśli używasz mtOM), a strumień dociera do EOF po odczytaniu zawartości.

Przesyłanie strumieniowe na poziomie transportu współpracuje również z dowolnym innym typem kontraktu komunikatów (listami parametrów, argumentami kontraktu danych i jawnym kontraktem komunikatów), ale ponieważ serializacja i deserializacji takich typowych komunikatów wymaga buforowania przez serializator, użycie takich wariantów kontraktu nie jest zalecane.

Specjalne zagadnienia dotyczące zabezpieczeń dla dużych danych

Wszystkie powiązania umożliwiają ograniczenie rozmiaru komunikatów przychodzących, aby zapobiec atakom typu "odmowa usługi". Na BasicHttpBindingprzykład właściwość System.ServiceModel.BasicHttpBinding.MaxReceivedMessageSize , która wiąże rozmiar komunikatu przychodzącego, a więc wiąże maksymalną ilość pamięci, która jest uzyskiwana podczas przetwarzania komunikatu. Ta lekcja jest ustawiana w bajtach z wartością domyślną 65 536 bajtów.

Zagrożenie bezpieczeństwa specyficzne dla scenariusza przesyłania strumieniowego dużych danych powoduje odmowę usługi, powodując buforowanie danych, gdy odbiorca oczekuje jego przesyłania strumieniowego. Na przykład usługa WCF zawsze buforuje nagłówki protokołu SOAP komunikatu, dlatego osoba atakująca może utworzyć duży złośliwy komunikat, który składa się całkowicie z nagłówków, aby wymusić buforowanie danych. Po włączeniu przesyłania strumieniowego parametr może być ustawiony na bardzo dużą wartość, MaxReceivedMessageSize ponieważ odbiornik nigdy nie oczekuje buforowania całego komunikatu w pamięci jednocześnie. Jeśli program WCF jest zmuszony do buforowania komunikatu, występuje przepełnienie pamięci.

Dlatego ograniczenie maksymalnego rozmiaru komunikatów przychodzących nie jest wystarczające w tym przypadku. Właściwość jest wymagana MaxBufferSize do ograniczenia pamięci buforów programu WCF. Ważne jest, aby ustawić tę wartość na bezpieczną wartość (lub zachować ją na wartości domyślnej) podczas przesyłania strumieniowego. Załóżmy na przykład, że usługa musi odbierać pliki o rozmiarze do 4 GB i przechowywać je na dysku lokalnym. Załóżmy również, że pamięć jest ograniczona w taki sposób, że jednocześnie można buforować tylko 64 KB danych. Następnie należy ustawić wartość MaxReceivedMessageSize 4 GB i MaxBufferSize na 64 KB. Ponadto w implementacji usługi należy upewnić się, że odczytasz tylko ze strumienia przychodzącego we fragmentach 64 KB i nie odczytaj kolejnego fragmentu, zanim poprzedni został zapisany na dysku i odrzucony z pamięci.

Należy również pamiętać, że ten limit przydziału ogranicza buforowanie wykonywane przez usługę WCF i nie może chronić cię przed buforowaniem wykonywanym we własnej usłudze lub implementacji klienta. Aby uzyskać więcej informacji na temat dodatkowych zagadnień dotyczących zabezpieczeń, zobacz Zagadnienia dotyczące zabezpieczeń danych.

Uwaga

Decyzja o użyciu buforowanych lub przesyłanych strumieniowo transferów jest lokalną decyzją punktu końcowego. W przypadku transportu HTTP tryb transferu nie jest propagowany przez połączenie ani do serwerów proxy i innych pośredników. Ustawienie trybu transferu nie jest odzwierciedlane w opisie interfejsu usługi. Po wygenerowaniu klienta programu WCF do usługi należy edytować plik konfiguracji usług przeznaczonych do użycia z transferami strumieniowymi, aby ustawić tryb. W przypadku transportu tcp i nazwanych potoków tryb transferu jest propagowany jako asercji zasad.

Zobacz też