方法: ストリーミングを有効にする
Windows Communication Foundation (WCF) では、バッファーまたはストリーム転送を使用してメッセージを送信できます。 既定のバッファー転送モードでは、受信側がメッセージを読み取る前に、メッセージの送信が完了している必要があります。 ストリーミング転送モードでは、送信が完了していなくても、受信側でメッセージの処理を開始できます。 ストリーミング モードは、渡される情報が長い場合、または連続的に処理する場合に役立ちます。 ストリーミング モードは、メッセージが大きすぎてすべてをバッファーできない場合にも役立ちます。
ストリーミングを有効にするには、OperationContract
を適切に定義し、トランスポート レベルでストリーミングを有効にします。
データをストリーミングするには
データをストリーミングするには、サービスの
OperationContract
が次の 2 つの要件を満たしている必要があります。ストリーミングするデータを保持するパラメーターが、メソッド内の唯一のパラメーターになるようにします。 たとえば、入力メッセージをストリーミングする場合、厳密に 1 つの入力パラメーターが操作に含まれている必要があります。 同様に、出力メッセージをストリーミングする場合、厳密に 1 つの出力パラメーターまたは戻り値が操作に含まれている必要があります。
パラメーターおよび戻り値の型の少なくとも 1 つが、Stream、Message または IXmlSerializable になる必要があります。
ストリーミングされたデータのコントラクトの例を次に示します。
[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(); }
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _ Public Interface IStreamingSample <OperationContract()> _ Function GetStream(ByVal data As String) As Stream <OperationContract()> _ Function UploadStream(ByVal stream As Stream) As Boolean <OperationContract()> _ Function EchoStream(ByVal stream As Stream) As Stream <OperationContract()> _ Function GetReversedStream() As Stream End Interface
GetStream
操作は、バッファーされた入力データをstring
として受信し、ストリーミングされたStream
を返します。 逆に言えば、UploadStream
はStream
(ストリーミング) を取り込んで、bool
(バッファー) を返します。EchoStream
はStream
を出し入れします。これは、入力および出力メッセージがどちらもストリーミングされる操作の例です。 最後に、GetReversedStream
は入力を行わずにStream
(ストリーミング) を返します。バインディングではストリーミングを有効にする必要があります。
TransferMode
プロパティを次の値のいずれかに設定します。Buffered
、Streamed
(両方向のストリーミング通信を有効にする)。StreamedRequest
(要求に対してのみストリーミングを有効にする)。StreamedResponse
(応答に対してのみストリーミングを有効にする)。
BasicHttpBinding
は、バインディングのTransferMode
プロパティを公開し、NetTcpBinding
とNetNamedPipeBinding
も公開します。TransferMode
プロパティをトランスポート バインド要素に設定し、カスタム バインドで使用することもできます。次のサンプルは、コードで
TransferMode
を設定する方法と、構成ファイルを変更して設定する方法を示しています。 どちらのサンプルも、受信可能なメッセージの最大サイズを決定するmaxReceivedMessageSize
プロパティを 64 MB に設定します。 既定のmaxReceivedMessageSize
は 64 KB です。これは、多くの場合ストリーミングを行うには小さすぎます。 アプリケーションでの受信が予想されるメッセージ最大サイズに応じて、このクォータ設定を適切に変更してください。 また、maxBufferSize
によりバッファーの最大サイズが決定されるので、適切に設定してください。次のサンプルの構成スニペットでは、
TransferMode
とカスタム HTTP バインディングで、basicHttpBinding
プロパティをストリーミングに設定しています。<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>
次のコード スニペットでは、
TransferMode
とカスタム HTTP バインディングで、basicHttpBinding
プロパティをストリーミングに設定しています。public static Binding CreateStreamingBinding() { BasicHttpBinding b = new BasicHttpBinding(); b.TransferMode = TransferMode.Streamed; return b; }
Public Shared Function CreateStreamingBinding() As Binding Dim b As New BasicHttpBinding() b.TransferMode = TransferMode.Streamed Return b End Function
次のコード スニペットでは、カスタム TCP バインディングで、
TransferMode
プロパティをストリーミングに設定しています。public static Binding CreateStreamingBinding() { TcpTransportBindingElement transport = new TcpTransportBindingElement(); transport.TransferMode = TransferMode.Streamed; BinaryMessageEncodingBindingElement encoder = new BinaryMessageEncodingBindingElement(); CustomBinding binding = new CustomBinding(encoder, transport); return binding; }
Public Shared Function CreateStreamingBinding() As Binding Dim transport As New TcpTransportBindingElement() transport.TransferMode = TransferMode.Streamed Dim binding As New CustomBinding(New BinaryMessageEncodingBindingElement(), _ transport) Return binding End Function
GetStream
、UploadStream
、およびEchoStream
の各操作では、ファイルからデータを直接送信したり、受信したデータを直接ファイルに保存します。 次のコードは、GetStream
の例です。public Stream GetStream(string data) { //this file path assumes the image is in // the Service folder and the service is executing // in service/bin string filePath = Path.Combine( System.Environment.CurrentDirectory, ".\\..\\image.jpg"); //open the file, this could throw an exception //(e.g. if the file is not found) //having includeExceptionDetailInFaults="True" in config // would cause this exception to be returned to the client try { FileStream imageFile = File.OpenRead(filePath); return imageFile; } catch (IOException ex) { Console.WriteLine( String.Format("An exception was thrown while trying to open file {0}", filePath)); Console.WriteLine("Exception is: "); Console.WriteLine(ex.ToString()); throw ex; } }
Public Function GetStream(ByVal data As String) As Stream Implements IStreamingSample.GetStream 'this file path assumes the image is in ' the Service folder and the service is executing ' in service/bin Dim filePath = Path.Combine(System.Environment.CurrentDirectory, ".\..\image.jpg") 'open the file, this could throw an exception '(e.g. if the file is not found) 'having includeExceptionDetailInFaults="True" in config ' would cause this exception to be returned to the client Try Return File.OpenRead(filePath) Catch ex As IOException Console.WriteLine(String.Format("An exception was thrown while trying to open file {0}", filePath)) Console.WriteLine("Exception is: ") Console.WriteLine(ex.ToString()) Throw ex End Try End Function
カスタム ストリームの書き込み
送受信中のデータ ストリームの各チャンクに対して特殊な処理を行うには、Stream からカスタム ストリーム クラスを派生します。 カスタム ストリームの例として、
GetReversedStream
メソッドとReverseStream
クラスのコードを次に示します。GetReversedStream
では、ReverseStream
の新しいインスタンスを作成して返します。 実際の処理は、システムがReverseStream
オブジェクトの読み取りを行うときに発生します。ReverseStream.Read
メソッドは、基になるファイルからバイトのチャンクを読み取り、バイトを反転し、その反転したバイトを返します。 このメソッドは、ファイル全体の内容を反転しません。一度に 1 つのバイト チャンクを反転します。 この例では、ストリームの内容の読み取りやストリームへの書き込み時に、ストリーミング処理を実行する方法を示します。class ReverseStream : Stream { FileStream inStream; internal ReverseStream(string filePath) { //opens the file and places a StreamReader around it inStream = File.OpenRead(filePath); } public override bool CanRead { get { return inStream.CanRead; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return false; } } public override void Flush() { throw new Exception("This stream does not support writing."); } public override long Length { get { throw new Exception("This stream does not support the Length property."); } } public override long Position { get { return inStream.Position; } set { throw new Exception("This stream does not support setting the Position property."); } } 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 long Seek(long offset, SeekOrigin origin) { throw new Exception("This stream does not support seeking."); } public override void SetLength(long value) { throw new Exception("This stream does not support setting the Length."); } public override void Write(byte[] buffer, int offset, int count) { throw new Exception("This stream does not support writing."); } 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; } } }
Friend Class ReverseStream Inherits Stream Private inStream As FileStream Friend Sub New(ByVal filePath As String) 'opens the file and places a StreamReader around it inStream = File.OpenRead(filePath) End Sub Public Overrides ReadOnly Property CanRead() As Boolean Get Return inStream.CanRead End Get End Property Public Overrides ReadOnly Property CanSeek() As Boolean Get Return False End Get End Property Public Overrides ReadOnly Property CanWrite() As Boolean Get Return False End Get End Property Public Overrides Sub Flush() Throw New Exception("This stream does not support writing.") End Sub Public Overrides ReadOnly Property Length() As Long Get Throw New Exception("This stream does not support the Length property.") End Get End Property Public Overrides Property Position() As Long Get Return inStream.Position End Get Set(ByVal value As Long) Throw New Exception("This stream does not support setting the Position property.") End Set End Property Public Overrides Function Read(ByVal buffer() As Byte, _ ByVal offset As Integer, _ ByVal count As Integer) As Integer Dim countRead = inStream.Read(buffer, _ offset, _ count) ReverseBuffer(buffer, _ offset, _ countRead) Return countRead End Function Public Overrides Function Seek(ByVal offset As Long, _ ByVal origin As SeekOrigin) As Long Throw New Exception("This stream does not support seeking.") End Function Public Overrides Sub SetLength(ByVal value As Long) Throw New Exception("This stream does not support setting the Length.") End Sub Public Overrides Sub Write(ByVal buffer() As Byte, _ ByVal offset As Integer, _ ByVal count As Integer) Throw New Exception("This stream does not support writing.") End Sub Public Overrides Sub Close() inStream.Close() MyBase.Close() End Sub Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) inStream.Dispose() MyBase.Dispose(disposing) End Sub Private Sub ReverseBuffer(ByVal buffer() As Byte, _ ByVal offset As Integer, _ ByVal count As Integer) Dim i = offset Dim j = offset + count - 1 Do While i < j Dim currenti = buffer(i) buffer(i) = buffer(j) buffer(j) = currenti i += 1 j -= 1 Loop End Sub End Class