Skip to content

Commit ebd86b0

Browse files
authored
Add Mtom Upload Stream test code (#5034)
1 parent 9596b4f commit ebd86b0

File tree

5 files changed

+188
-1
lines changed

5 files changed

+188
-1
lines changed

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"tools": {
33
"dotnet": "8.0.100-preview.3.23178.7",
44
"runtimes": {
5-
"dotnet": [
5+
"aspnetcore": [
66
"3.1.5",
77
"6.0.15",
88
"7.0.4"

src/System.Private.ServiceModel/tests/Common/Scenarios/ScenarioTestTypes.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,64 @@ public void OnDataContractPingCallback(ComplexCompositeTypeDuplexCallbackOnly da
947947
}
948948
}
949949

950+
public class BloatedStream : Stream
951+
{
952+
private readonly long _length;
953+
private long _position;
954+
955+
public BloatedStream(long length)
956+
{
957+
_length = length;
958+
_position = 0;
959+
}
960+
961+
public override bool CanRead => true;
962+
963+
public override bool CanSeek => false;
964+
965+
public override bool CanWrite => false;
966+
967+
public override long Length => throw new NotSupportedException();
968+
969+
public override long Position
970+
{
971+
get => throw new NotSupportedException();
972+
set => throw new NotSupportedException();
973+
}
974+
975+
public override void Flush()
976+
{
977+
throw new NotSupportedException();
978+
}
979+
980+
public override int Read(byte[] buffer, int offset, int count)
981+
{
982+
if (_position < _length)
983+
{
984+
var numberOfBytesInThisRead = (int)Math.Min(count, _length - _position);
985+
_position += numberOfBytesInThisRead;
986+
return numberOfBytesInThisRead;
987+
}
988+
989+
return 0;
990+
}
991+
992+
public override long Seek(long offset, SeekOrigin origin)
993+
{
994+
throw new NotSupportedException();
995+
}
996+
997+
public override void SetLength(long value)
998+
{
999+
throw new NotSupportedException();
1000+
}
1001+
1002+
public override void Write(byte[] buffer, int offset, int count)
1003+
{
1004+
throw new NotSupportedException();
1005+
}
1006+
}
1007+
9501008
public class FlowControlledStream : Stream
9511009
{
9521010
private ManualResetEvent _waitEvent = new ManualResetEvent(false);

src/System.Private.ServiceModel/tests/Scenarios/Binding/Http/BasicHttpBindingTests.4.0.0.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
using System;
66
using System.Collections.Generic;
7+
using System.Linq;
78
using System.Net.Http;
89
using System.ServiceModel;
910
using System.ServiceModel.Channels;
1011
using System.Threading.Tasks;
1112
using Infrastructure.Common;
13+
using Microsoft.AspNetCore.Builder;
14+
using Microsoft.Extensions.Hosting;
1215
using Xunit;
1316

1417
public static class Binding_Http_BasicHttpBindingTests
@@ -359,4 +362,44 @@ public static void DecompressionEnabled_Echo_RoundTrips_String(bool decompressio
359362
ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
360363
}
361364
}
365+
366+
[WcfTheory]
367+
[InlineData(65536)] // 64KB
368+
[InlineData(1048576)] // 1MB
369+
[InlineData(67108864)] // 64MB
370+
[InlineData(4294967296)] // 4GB
371+
[OuterLoop]
372+
public static async void DefaultSettings_Http_Mtom_Stream_Upload(long uploadBytes)
373+
{
374+
ChannelFactory<MtomBindingTestHelper.IMtomStreamingService> factory = null;
375+
MtomBindingTestHelper.IMtomStreamingService serviceProxy = null;
376+
377+
try
378+
{
379+
// *** SETUP *** \\
380+
// WCF Service
381+
await using (WebApplication app = MtomBindingTestHelper.BuildWCFService())
382+
{
383+
app.Start();
384+
385+
// WCF Client
386+
factory = new ChannelFactory<MtomBindingTestHelper.IMtomStreamingService>(
387+
MtomBindingTestHelper.CreateMtomClientBinding(),
388+
new EndpointAddress(app.Urls.First(u => u.StartsWith("http:"))));
389+
serviceProxy = factory.CreateChannel();
390+
391+
// *** EXECUTE *** \\
392+
long result = serviceProxy.UploadStream(new BloatedStream(uploadBytes));
393+
}
394+
395+
// *** CLEANUP *** \\
396+
factory.Close();
397+
((ICommunicationObject)serviceProxy).Close();
398+
}
399+
finally
400+
{
401+
// *** ENSURE CLEANUP *** \\
402+
ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
403+
}
404+
}
362405
}

src/System.Private.ServiceModel/tests/Scenarios/Binding/Http/Binding.Http.IntegrationTests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
<ProjectReference Include='$(WcfScenarioTestCommonProj)' />
1414
<ProjectReference Include="$(WcfInfrastructureCommonProj)" />
1515
</ItemGroup>
16+
17+
<ItemGroup>
18+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
19+
</ItemGroup>
1620
</Project>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.IO;
6+
using System.ServiceModel;
7+
using System.ServiceModel.Channels;
8+
using System.Text;
9+
using System.Xml;
10+
using Microsoft.AspNetCore.Builder;
11+
using Microsoft.AspNetCore.Hosting;
12+
using Microsoft.AspNetCore.Http;
13+
using Microsoft.AspNetCore.Http.Features;
14+
15+
public class MtomBindingTestHelper
16+
{
17+
[ServiceContract]
18+
public interface IMtomStreamingService
19+
{
20+
[OperationContract]
21+
long UploadStream(Stream stream);
22+
}
23+
24+
public class MtomStreamingService : IMtomStreamingService
25+
{
26+
public long UploadStream(Stream stream)
27+
{
28+
var buffer = new byte[65536];
29+
long totalBytes = 0;
30+
int bytesRead;
31+
32+
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
33+
{
34+
totalBytes += bytesRead;
35+
}
36+
37+
return totalBytes;
38+
}
39+
}
40+
41+
public static WebApplication BuildWCFService()
42+
{
43+
var builder = WebApplication.CreateBuilder();
44+
builder.WebHost.ConfigureKestrel(serverOptions =>
45+
{
46+
serverOptions.AllowSynchronousIO = true;
47+
serverOptions.Limits.MaxRequestBodySize = 5_368_709_120;
48+
});
49+
50+
var app = builder.Build();
51+
52+
app.MapPost("/", async (HttpContext context) =>
53+
{
54+
context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize = 5_368_709_120;
55+
var buffer = new byte[8192];
56+
while (await context.Request.Body.ReadAsync(buffer, 0, 8192) != 0) { }
57+
58+
context.Response.Headers.ContentType = "multipart/related; type=\"application/xop+xml\";start=\"<http://tempuri.org/0>\";boundary=\"uuid:fca834ef-6b4a-43c0-a7d0-09064d2827e8+id=1\";start-info=\"text/xml\"";
59+
await context.Response.WriteAsync("--uuid:fca834ef-6b4a-43c0-a7d0-09064d2827e8+id=1\r\nContent-ID: <http://tempuri.org/0>\r\nContent-Transfer-Encoding: 8bit\r\nContent-Type: application/xop+xml;charset=utf-8;type=\"text/xml\"\r\n\r\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><UploadStreamResponse xmlns=\"http://tempuri.org/\"></UploadStreamResponse></s:Body></s:Envelope>");
60+
});
61+
62+
return app;
63+
}
64+
65+
public static Binding CreateMtomClientBinding()
66+
{
67+
var binding = new CustomBinding();
68+
var mtomElement = new MtomMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
69+
XmlDictionaryReaderQuotas.Max.CopyTo(mtomElement.ReaderQuotas);
70+
binding.Elements.Add(mtomElement);
71+
binding.Elements.Add(new HttpTransportBindingElement
72+
{
73+
TransferMode = TransferMode.Streamed,
74+
MaxBufferSize = 1024 * 64,
75+
MaxBufferPoolSize = 1,
76+
MaxReceivedMessageSize = 5_368_709_120
77+
});
78+
binding.SendTimeout = TimeSpan.FromMinutes(5);
79+
binding.ReceiveTimeout = TimeSpan.FromMinutes(5);
80+
return binding;
81+
}
82+
}

0 commit comments

Comments
 (0)