-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add source code of Compression Message Encoder Sample
- Loading branch information
Showing
18 changed files
with
843 additions
and
0 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
Extensibility/MessageEncoder/Compression/Client/Client.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="System.ServiceModel" /> | ||
<Using Include="System.ServiceModel.Channels" /> | ||
<Using Include="CoreWcf.Samples.CompressionMessageEncoder" /> | ||
<Using Include="CoreWcf.Samples.GZipEncoder" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.ServiceModel.Http" Version="4.*" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\GZipEncoder\GZipEncoder.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
17 changes: 17 additions & 0 deletions
17
...Client/Connected Services/CoreWcf.Samples.CompressionMessageEncoder/ConnectedService.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"ExtendedData": { | ||
"inputs": [ | ||
"http://localhost:5000/gzipMessageEncoding?wsdl" | ||
], | ||
"collectionTypes": [ | ||
"System.Array", | ||
"System.Collections.Generic.Dictionary`2" | ||
], | ||
"namespaceMappings": [ | ||
"*, CoreWcf.Samples.CompressionMessageEncoder" | ||
], | ||
"sync": true, | ||
"targetFramework": "net6.0", | ||
"typeReuseMode": "All" | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
...pression/Client/Connected Services/CoreWcf.Samples.CompressionMessageEncoder/Reference.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
//------------------------------------------------------------------------------ | ||
// <auto-generated> | ||
// This code was generated by a tool. | ||
// | ||
// Changes to this file may cause incorrect behavior and will be lost if | ||
// the code is regenerated. | ||
// </auto-generated> | ||
//------------------------------------------------------------------------------ | ||
|
||
namespace CoreWcf.Samples.CompressionMessageEncoder | ||
{ | ||
|
||
|
||
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")] | ||
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="CoreWcf.Samples.CompressionMessageEncoder.IEchoService")] | ||
public interface IEchoService | ||
{ | ||
|
||
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEchoService/Echo", ReplyAction="http://tempuri.org/IEchoService/EchoResponse")] | ||
string Echo(string input); | ||
|
||
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEchoService/Echo", ReplyAction="http://tempuri.org/IEchoService/EchoResponse")] | ||
System.Threading.Tasks.Task<string> EchoAsync(string input); | ||
|
||
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEchoService/BigEcho", ReplyAction="http://tempuri.org/IEchoService/BigEchoResponse")] | ||
string[] BigEcho(string[] input); | ||
|
||
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEchoService/BigEcho", ReplyAction="http://tempuri.org/IEchoService/BigEchoResponse")] | ||
System.Threading.Tasks.Task<string[]> BigEchoAsync(string[] input); | ||
} | ||
|
||
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")] | ||
public interface IEchoServiceChannel : CoreWcf.Samples.CompressionMessageEncoder.IEchoService, System.ServiceModel.IClientChannel | ||
{ | ||
} | ||
|
||
[System.Diagnostics.DebuggerStepThroughAttribute()] | ||
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")] | ||
public partial class EchoServiceClient : System.ServiceModel.ClientBase<CoreWcf.Samples.CompressionMessageEncoder.IEchoService>, CoreWcf.Samples.CompressionMessageEncoder.IEchoService | ||
{ | ||
|
||
public EchoServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : | ||
base(binding, remoteAddress) | ||
{ | ||
} | ||
|
||
public string Echo(string input) | ||
{ | ||
return base.Channel.Echo(input); | ||
} | ||
|
||
public System.Threading.Tasks.Task<string> EchoAsync(string input) | ||
{ | ||
return base.Channel.EchoAsync(input); | ||
} | ||
|
||
public string[] BigEcho(string[] input) | ||
{ | ||
return base.Channel.BigEcho(input); | ||
} | ||
|
||
public System.Threading.Tasks.Task<string[]> BigEchoAsync(string[] input) | ||
{ | ||
return base.Channel.BigEchoAsync(input); | ||
} | ||
|
||
public virtual System.Threading.Tasks.Task OpenAsync() | ||
{ | ||
return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndOpen)); | ||
} | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
Extensibility/MessageEncoder/Compression/Client/Program.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
//The service contract is defined using Connected Service "WCF Web Service", generated from the service by the dotnet svcutil tool. | ||
|
||
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(); | ||
HttpTransportBindingElement httpTransportBindingElement = basicHttpBinding.CreateBindingElements().Find<HttpTransportBindingElement>(); | ||
MessageEncodingBindingElement encodingBindingElement = new GZipMessageEncodingBindingElement(); | ||
CustomBinding binding = new CustomBinding(new BindingElement[] | ||
{ | ||
encodingBindingElement, | ||
httpTransportBindingElement | ||
}); | ||
|
||
var endpointAddress = new EndpointAddress("http://localhost:5000/gzipMessageEncoding"); | ||
|
||
// Create a client with given client endpoint configuration | ||
EchoServiceClient client = new EchoServiceClient(binding, endpointAddress); | ||
|
||
Console.WriteLine("Calling Echo(string):"); | ||
Console.WriteLine("Server responds: {0}", client.Echo("Simple hello")); | ||
|
||
Console.WriteLine(); | ||
Console.WriteLine("Calling BigEcho(string[]):"); | ||
string[] messages = new string[64]; | ||
for (int i = 0; i < 64; i++) | ||
{ | ||
messages[i] = "Hello " + i; | ||
} | ||
|
||
Console.WriteLine("Server responds: {0}", client.BigEcho(messages)); | ||
|
||
//Closing the client gracefully closes the connection and cleans up resources | ||
client.Close(); | ||
|
||
Console.WriteLine(); | ||
Console.WriteLine("Press <ENTER> to terminate client."); | ||
Console.ReadLine(); |
43 changes: 43 additions & 0 deletions
43
Extensibility/MessageEncoder/Compression/Extensibility.MessageEncoder.Compression.sln
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.2.32422.2 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Service", "Service\Service.csproj", "{BF126326-3393-407C-B24A-8FCCC388BE27}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{B533CADA-93BB-40E1-8FBA-FE37100062C3}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GZipEncoder", "GZipEncoder\GZipEncoder.csproj", "{D1EAF072-0F66-4BD0-BC53-D4ABC45163C5}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GZipEncoderCoreWCF", "GZipEncoderCoreWCF\GZipEncoderCoreWCF.csproj", "{5DA1D92E-E835-49B7-8009-BD75E1ECC050}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{BF126326-3393-407C-B24A-8FCCC388BE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{BF126326-3393-407C-B24A-8FCCC388BE27}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{BF126326-3393-407C-B24A-8FCCC388BE27}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{BF126326-3393-407C-B24A-8FCCC388BE27}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{D1EAF072-0F66-4BD0-BC53-D4ABC45163C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{D1EAF072-0F66-4BD0-BC53-D4ABC45163C5}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{D1EAF072-0F66-4BD0-BC53-D4ABC45163C5}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{D1EAF072-0F66-4BD0-BC53-D4ABC45163C5}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{5DA1D92E-E835-49B7-8009-BD75E1ECC050}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{5DA1D92E-E835-49B7-8009-BD75E1ECC050}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{5DA1D92E-E835-49B7-8009-BD75E1ECC050}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{5DA1D92E-E835-49B7-8009-BD75E1ECC050}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {AD996EFD-70DC-4431-B411-5A2771DD02D3} | ||
EndGlobalSection | ||
EndGlobal |
18 changes: 18 additions & 0 deletions
18
Extensibility/MessageEncoder/Compression/GZipEncoder/GZipEncoder.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="System.ServiceModel" /> | ||
<Using Include="System.ServiceModel.Channels" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.ServiceModel.Http" Version="4.*" /> | ||
</ItemGroup> | ||
|
||
</Project> |
147 changes: 147 additions & 0 deletions
147
Extensibility/MessageEncoder/Compression/GZipEncoder/GZipMessageEncoderFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
| ||
using System.IO.Compression; | ||
|
||
namespace CoreWcf.Samples.GZipEncoder | ||
{ | ||
//This class is used to create the custom encoder (GZipMessageEncoder) | ||
internal class GZipMessageEncoderFactory : MessageEncoderFactory | ||
{ | ||
private readonly MessageEncoder _encoder; | ||
|
||
//The GZip encoder wraps an inner encoder | ||
//We require a factory to be passed in that will create this inner encoder | ||
public GZipMessageEncoderFactory(MessageEncoderFactory messageEncoderFactory) | ||
{ | ||
if (messageEncoderFactory == null) | ||
throw new ArgumentNullException(nameof(messageEncoderFactory), "A valid message encoder factory must be passed to the GZipEncoder"); | ||
_encoder = new GZipMessageEncoder(messageEncoderFactory.Encoder); | ||
} | ||
|
||
//The service framework uses this property to obtain an encoder from this encoder factory | ||
public override MessageEncoder Encoder => _encoder; | ||
|
||
public override MessageVersion MessageVersion => _encoder.MessageVersion; | ||
|
||
//This is the actual GZip encoder | ||
public class GZipMessageEncoder : MessageEncoder | ||
{ | ||
private static readonly string s_gZipContentType = "application/x-gzip"; | ||
|
||
//This implementation wraps an inner encoder that actually converts a WCF Message | ||
//into textual XML, binary XML or some other format. This implementation then compresses the results. | ||
//The opposite happens when reading messages. | ||
//This member stores this inner encoder. | ||
private readonly MessageEncoder _innerEncoder; | ||
|
||
//We require an inner encoder to be supplied (see comment above) | ||
internal GZipMessageEncoder(MessageEncoder messageEncoder) | ||
: base() | ||
{ | ||
_innerEncoder = messageEncoder ?? throw new ArgumentNullException(nameof(messageEncoder), "A valid message encoder must be passed to the GZipEncoder"); | ||
} | ||
|
||
public override string ContentType => s_gZipContentType; | ||
|
||
public override string MediaType => s_gZipContentType; | ||
|
||
//SOAP version to use - we delegate to the inner encoder for this | ||
public override MessageVersion MessageVersion => _innerEncoder.MessageVersion; | ||
|
||
//Helper method to compress an array of bytes | ||
static ArraySegment<byte> CompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager, int messageOffset) | ||
{ | ||
MemoryStream memoryStream = new MemoryStream(); | ||
|
||
using (GZipStream gzStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) | ||
{ | ||
gzStream.Write(buffer.Array, buffer.Offset, buffer.Count); | ||
} | ||
|
||
byte[] compressedBytes = memoryStream.ToArray(); | ||
int totalLength = messageOffset + compressedBytes.Length; | ||
byte[] bufferedBytes = bufferManager.TakeBuffer(totalLength); | ||
|
||
Array.Copy(compressedBytes, 0, bufferedBytes, messageOffset, compressedBytes.Length); | ||
|
||
bufferManager.ReturnBuffer(buffer.Array); | ||
ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferedBytes, messageOffset, bufferedBytes.Length - messageOffset); | ||
|
||
return byteArray; | ||
} | ||
|
||
//Helper method to decompress an array of bytes | ||
static ArraySegment<byte> DecompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager) | ||
{ | ||
MemoryStream memoryStream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count); | ||
MemoryStream decompressedStream = new MemoryStream(); | ||
int totalRead = 0; | ||
int blockSize = 1024; | ||
byte[] tempBuffer = bufferManager.TakeBuffer(blockSize); | ||
using (GZipStream gzStream = new GZipStream(memoryStream, CompressionMode.Decompress)) | ||
{ | ||
while (true) | ||
{ | ||
int bytesRead = gzStream.Read(tempBuffer, 0, blockSize); | ||
if (bytesRead == 0) | ||
break; | ||
decompressedStream.Write(tempBuffer, 0, bytesRead); | ||
totalRead += bytesRead; | ||
} | ||
} | ||
bufferManager.ReturnBuffer(tempBuffer); | ||
|
||
byte[] decompressedBytes = decompressedStream.ToArray(); | ||
byte[] bufferManagerBuffer = bufferManager.TakeBuffer(decompressedBytes.Length + buffer.Offset); | ||
Array.Copy(buffer.Array, 0, bufferManagerBuffer, 0, buffer.Offset); | ||
Array.Copy(decompressedBytes, 0, bufferManagerBuffer, buffer.Offset, decompressedBytes.Length); | ||
|
||
ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferManagerBuffer, buffer.Offset, decompressedBytes.Length); | ||
bufferManager.ReturnBuffer(buffer.Array); | ||
|
||
return byteArray; | ||
} | ||
|
||
//One of the two main entry points into the encoder. Called by WCF to decode a buffered byte array into a Message. | ||
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) | ||
{ | ||
//Decompress the buffer | ||
ArraySegment<byte> decompressedBuffer = DecompressBuffer(buffer, bufferManager); | ||
//Use the inner encoder to decode the decompressed buffer | ||
Message returnMessage = _innerEncoder.ReadMessage(decompressedBuffer, bufferManager); | ||
returnMessage.Properties.Encoder = this; | ||
return returnMessage; | ||
} | ||
|
||
//One of the two main entry points into the encoder. Called by WCF to encode a Message into a buffered byte array. | ||
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) | ||
{ | ||
//Use the inner encoder to encode a Message into a buffered byte array | ||
ArraySegment<byte> buffer = _innerEncoder.WriteMessage(message, maxMessageSize, bufferManager, 0); | ||
//Compress the resulting byte array | ||
return CompressBuffer(buffer, bufferManager, messageOffset); | ||
} | ||
|
||
public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType) | ||
{ | ||
//Pass false for the "leaveOpen" parameter to the GZipStream constructor. | ||
//This will ensure that the inner stream gets closed when the message gets closed, which | ||
//will ensure that resources are available for reuse/release. | ||
GZipStream gzStream = new GZipStream(stream, CompressionMode.Decompress, false); | ||
return _innerEncoder.ReadMessage(gzStream, maxSizeOfHeaders); | ||
} | ||
|
||
public override void WriteMessage(Message message, System.IO.Stream stream) | ||
{ | ||
using (GZipStream gzStream = new GZipStream(stream, CompressionMode.Compress, true)) | ||
{ | ||
_innerEncoder.WriteMessage(message, gzStream); | ||
} | ||
|
||
// innerEncoder.WriteMessage(message, gzStream) depends on that it can flush data by flushing | ||
// the stream passed in, but the implementation of GZipStream.Flush will not flush underlying | ||
// stream, so we need to flush here. | ||
stream.Flush(); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.