diff --git a/issue1161/MyMessage.cs b/issue1161/MyMessage.cs new file mode 100644 index 00000000..9b3c5e82 --- /dev/null +++ b/issue1161/MyMessage.cs @@ -0,0 +1,40 @@ +using System.ServiceModel; +using System.Xml; +using System.Xml.Serialization; + +[MessageContract] +public class MyMessage { + private string _body; + + [MessageHeader(Name = "MessageHeader", Namespace = "http://www.ebxml.org/namespaces/messageHeader")] + public MyMessageHeader Header { get; set; } + + [MessageBodyMember] + public string BodyMessage + { + get => _body; + set => _body = value; + } +} + + +[XmlType(AnonymousType = true, Namespace = "http://www.ebxml.org/namespaces/messageHeader")] +public class MyMessageHeader +{ + private string _from; + private XmlAttribute[] _anyAttr; + + [XmlElement(Order = 0)] + public string From + { + get => _from; + set => _from = value; + } + + [XmlAnyAttribute] + public XmlAttribute[] SomeOtherAttributes + { + get => _anyAttr; + set => _anyAttr = value; + } +} diff --git a/issue1161/MySoapService.cs b/issue1161/MySoapService.cs new file mode 100644 index 00000000..4372b1ed --- /dev/null +++ b/issue1161/MySoapService.cs @@ -0,0 +1,17 @@ +using System.ServiceModel; + +[ServiceContract] +public interface IMySoapService +{ + [OperationContract] + MyMessage Process(MyMessage rq); +} + +public class MySoapService : IMySoapService +{ + public MyMessage Process(MyMessage msg) + { + return msg; + } + +} diff --git a/issue1161/Program.cs b/issue1161/Program.cs new file mode 100644 index 00000000..c460653a --- /dev/null +++ b/issue1161/Program.cs @@ -0,0 +1,22 @@ +using System.ServiceModel.Channels; +using SoapCore; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddSoapCore(); +builder.Services.AddSingleton(); + +var app = builder.Build(); + + +app.UseRouting(); +app.UseEndpoints(endpoints => +{ + endpoints.UseSoapEndpoint("/myService", new SoapEncoderOptions() + { + MessageVersion = MessageVersion.Soap11 + }, + SoapSerializer.XmlSerializer); +}); + +app.Run(); diff --git a/issue1161/Properties/launchSettings.json b/issue1161/Properties/launchSettings.json new file mode 100644 index 00000000..09c64487 --- /dev/null +++ b/issue1161/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:15581", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "myService", + "applicationUrl": "http://localhost:5220", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "myService", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/issue1161/SoapCore-Issue-1161.csproj b/issue1161/SoapCore-Issue-1161.csproj new file mode 100644 index 00000000..6d2f715b --- /dev/null +++ b/issue1161/SoapCore-Issue-1161.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + SoapCore_Issue_1161 + + + + + + + diff --git a/issue1161/SoapCore-Issue-1161.http b/issue1161/SoapCore-Issue-1161.http new file mode 100644 index 00000000..c8db17c7 --- /dev/null +++ b/issue1161/SoapCore-Issue-1161.http @@ -0,0 +1,46 @@ +@SoapCore_Issue_1161_HostAddress = http://localhost:5220 + +### Get WSDL +GET {{SoapCore_Issue_1161_HostAddress}}/myService +Accept: application/json + + +### Test SOAP ProcessUser (passes) +POST {{SoapCore_Issue_1161_HostAddress}}/myService +Content-Type: text/xml; charset=utf-8 +SOAPAction: "http://tempuri.org/IMySoapService/Process" + + + + + + SomeSender + + + + + someBody + + + + +### Test SOAP ProcessUser (fails with SoapCore 1.2.1) +POST {{SoapCore_Issue_1161_HostAddress}}/myService +Content-Type: text/xml; charset=utf-8 +SOAPAction: "http://tempuri.org/IMySoapService/Process" + + + + + + SomeSender + + + + + someBody + + + + diff --git a/issue1161/appsettings.Development.json b/issue1161/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/issue1161/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/issue1161/appsettings.json b/issue1161/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/issue1161/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/SoapCore.Tests/ITestService.cs b/src/SoapCore.Tests/ITestService.cs index 1682cbcd..233bec5d 100644 --- a/src/SoapCore.Tests/ITestService.cs +++ b/src/SoapCore.Tests/ITestService.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SoapCore.Tests.Model; +using SoapCore.Tests.Serialization.Models.DataContract; namespace SoapCore.Tests { @@ -106,6 +107,9 @@ public interface ITestService [OperationContract] XmlElement XmlElementInput(XmlElement input); + [OperationContract] + MessageHeadersModelWithDuplicateNamespaces GetWithDuplicateNamespaces(MessageHeadersModelWithDuplicateNamespaces input); + /// /// Return type is different than the one bellow due to customizations. Use SoapCore.Tests.NativeAuthenticationAndAuthorization.IActionResultContractService to access these endpoints. /// diff --git a/src/SoapCore.Tests/IntegrationTests.cs b/src/SoapCore.Tests/IntegrationTests.cs index 851626fe..48ed651b 100644 --- a/src/SoapCore.Tests/IntegrationTests.cs +++ b/src/SoapCore.Tests/IntegrationTests.cs @@ -247,6 +247,20 @@ public void XmlElemetInput() Assert.IsTrue(output.OuterXml.Contains("Success")); } + [TestMethod] + public void MessageWithDuplicateNamespace() + { + var client = CreateClient(); + var output = client.GetWithDuplicateNamespaces(new () + { + BodyMessage = "test", + Header = new () { From = "test" } + }); + + Assert.AreEqual("test", output.BodyMessage); + Assert.AreEqual("test", output.Header.From); + } + [TestMethod] public void ThrowsFaultException() { diff --git a/src/SoapCore.Tests/Serialization/MessageHeadersTests.cs b/src/SoapCore.Tests/Serialization/MessageHeadersTests.cs index 40de5ae3..1a535b4f 100644 --- a/src/SoapCore.Tests/Serialization/MessageHeadersTests.cs +++ b/src/SoapCore.Tests/Serialization/MessageHeadersTests.cs @@ -149,5 +149,37 @@ public void TestMessageHeadersModelWithNamespace(SoapSerializer serializer) Assert.Equal(model.Prop3, result.Prop3); Assert.Equal(model.Prop4, result.Prop4); } + + [Theory] + [InlineData(SoapSerializer.XmlSerializer)] + public void TestMessageWithDuplicateNamespace(SoapSerializer serializer) + { + var service = _fixture.GetSampleServiceClient(serializer); + var model = new MessageHeadersModelWithDuplicateNamespaces + { + BodyMessage = "test", + Header = new MessageHeadersModelWithDuplicateNamespacesHeader() + { + From = "test" + } + }; + + _fixture.ServiceMock.Setup(x => x.GetWithDuplicateNamespaces(It.IsAny())).Callback((MessageHeadersModelWithDuplicateNamespaces m) => + { + m.ShouldDeepEqual(model); + }).Returns(new MessageHeadersModelWithDuplicateNamespaces + { + BodyMessage = "test", + Header = new MessageHeadersModelWithDuplicateNamespacesHeader() + { + From = "test" + } + }); + + var result = service.GetWithDuplicateNamespaces(model); + + Assert.Equal(model.BodyMessage, result.BodyMessage); + Assert.Equal(model.Header.From, result.Header.From); + } } } diff --git a/src/SoapCore.Tests/Serialization/Models.DataContract/ISampleServiceWithMessageHeaders.cs b/src/SoapCore.Tests/Serialization/Models.DataContract/ISampleServiceWithMessageHeaders.cs index 6101f095..15f60354 100644 --- a/src/SoapCore.Tests/Serialization/Models.DataContract/ISampleServiceWithMessageHeaders.cs +++ b/src/SoapCore.Tests/Serialization/Models.DataContract/ISampleServiceWithMessageHeaders.cs @@ -13,5 +13,8 @@ public interface ISampleServiceWithMessageHeaders [OperationContract] MessageHeadersModelWithNamespace GetWithNamespace(MessageHeadersModelWithNamespace model); + + [OperationContract] + MessageHeadersModelWithDuplicateNamespaces GetWithDuplicateNamespaces(MessageHeadersModelWithDuplicateNamespaces input); } } diff --git a/src/SoapCore.Tests/Serialization/Models.DataContract/MessageHeadersModelWithDuplicateNamespaces.cs b/src/SoapCore.Tests/Serialization/Models.DataContract/MessageHeadersModelWithDuplicateNamespaces.cs new file mode 100644 index 00000000..4673d1bb --- /dev/null +++ b/src/SoapCore.Tests/Serialization/Models.DataContract/MessageHeadersModelWithDuplicateNamespaces.cs @@ -0,0 +1,14 @@ +using System.Runtime.Serialization; +using System.ServiceModel; + +namespace SoapCore.Tests.Serialization.Models.DataContract; + +[MessageContract] +public class MessageHeadersModelWithDuplicateNamespaces +{ + [MessageHeader(Name = "MessageHeader", Namespace = "MessageWithNamespacesHeaderNamespace")] + public MessageHeadersModelWithDuplicateNamespacesHeader Header { get; set; } + + [MessageBodyMember] + public string BodyMessage { get; set; } +} diff --git a/src/SoapCore.Tests/Serialization/Models.DataContract/MessageHeadersModelWithDuplicateNamespacesHeader.cs b/src/SoapCore.Tests/Serialization/Models.DataContract/MessageHeadersModelWithDuplicateNamespacesHeader.cs new file mode 100644 index 00000000..c136cedc --- /dev/null +++ b/src/SoapCore.Tests/Serialization/Models.DataContract/MessageHeadersModelWithDuplicateNamespacesHeader.cs @@ -0,0 +1,14 @@ +using System.Xml; +using System.Xml.Serialization; + +namespace SoapCore.Tests.Serialization.Models.DataContract; + +[XmlType(AnonymousType = true, Namespace = "MessageWithNamespacesHeaderNamespace")] +public class MessageHeadersModelWithDuplicateNamespacesHeader +{ + [XmlElement(Order = 0)] + public string From { get; set; } + + [XmlAnyAttribute] + public XmlAttribute[] SomeOtherAttributes { get; set; } +} diff --git a/src/SoapCore.Tests/SoapCore.Tests.csproj b/src/SoapCore.Tests/SoapCore.Tests.csproj index 26ae0353..6eef1d00 100644 --- a/src/SoapCore.Tests/SoapCore.Tests.csproj +++ b/src/SoapCore.Tests/SoapCore.Tests.csproj @@ -54,7 +54,7 @@ all runtime; build; native; contentfiles; analyzers - + diff --git a/src/SoapCore.Tests/TestService.cs b/src/SoapCore.Tests/TestService.cs index de53c085..8cded9a1 100644 --- a/src/SoapCore.Tests/TestService.cs +++ b/src/SoapCore.Tests/TestService.cs @@ -7,6 +7,7 @@ using System.Xml; using Microsoft.AspNetCore.Mvc; using SoapCore.Tests.Model; +using SoapCore.Tests.Serialization.Models.DataContract; namespace SoapCore.Tests { @@ -366,5 +367,10 @@ public ActionResult JwtAuthenticationAndAuthorizationComplexG }; } } + + public MessageHeadersModelWithDuplicateNamespaces GetWithDuplicateNamespaces(MessageHeadersModelWithDuplicateNamespaces input) + { + return input; + } } } diff --git a/src/SoapCore.sln b/src/SoapCore.sln index 4dc72098..51ce53cb 100644 --- a/src/SoapCore.sln +++ b/src/SoapCore.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2036 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36705.20 d17.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoapCore", "SoapCore\SoapCore.csproj", "{576F47D4-97EC-4D42-8CD5-89648EEAB688}" EndProject @@ -8,6 +8,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoapCore.Tests", "SoapCore. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoapCore.Benchmark", "SoapCore.Benchmark\SoapCore.Benchmark.csproj", "{B54A69DB-ADA2-48E0-A0D7-7649EDA987E1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoapCore-Issue-1161", "..\issue1161\SoapCore-Issue-1161.csproj", "{26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,6 +56,18 @@ Global {B54A69DB-ADA2-48E0-A0D7-7649EDA987E1}.Release|x64.Build.0 = Release|Any CPU {B54A69DB-ADA2-48E0-A0D7-7649EDA987E1}.Release|x86.ActiveCfg = Release|Any CPU {B54A69DB-ADA2-48E0-A0D7-7649EDA987E1}.Release|x86.Build.0 = Release|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Debug|x64.ActiveCfg = Debug|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Debug|x64.Build.0 = Debug|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Debug|x86.ActiveCfg = Debug|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Debug|x86.Build.0 = Debug|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Release|Any CPU.Build.0 = Release|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Release|x64.ActiveCfg = Release|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Release|x64.Build.0 = Release|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Release|x86.ActiveCfg = Release|Any CPU + {26918EE6-B839-7C0E-D4D1-5C9BAD20B69F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE