diff --git a/src/SoapCore.Tests/RawRequestSoap12Tests.cs b/src/SoapCore.Tests/RawRequestSoap12Tests.cs index 565657a0..d9d84afe 100644 --- a/src/SoapCore.Tests/RawRequestSoap12Tests.cs +++ b/src/SoapCore.Tests/RawRequestSoap12Tests.cs @@ -46,6 +46,56 @@ public void Soap12PingWithActionInHeader() } } + [TestMethod] + public void Soap12PingWithNamespaceDeclarationsRepeatedOnBody() + { + var body = @" + + + + abc + + + +"; + var bodyBytes = Encoding.UTF8.GetBytes(body); + using (var host = CreateTestHost()) + using (var client = host.CreateClient()) + using (var content = new StringContent(body, Encoding.UTF8, "application/soap+xml")) + { + content.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("action", "\"http://tempuri.org/ITestService/Ping\"")); + using (var res = host.CreateRequest("/Service.svc").And(msg => msg.Content = content).PostAsync().Result) + { + res.EnsureSuccessStatusCode(); + } + } + } + + [TestMethod] + public void Soap12PingWithPrefixShadowedOnBody() + { + var body = @" + + + + abc + + + +"; + var bodyBytes = Encoding.UTF8.GetBytes(body); + using (var host = CreateTestHost()) + using (var client = host.CreateClient()) + using (var content = new StringContent(body, Encoding.UTF8, "application/soap+xml")) + { + content.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("action", "\"http://tempuri.org/ITestService/Ping\"")); + using (var res = host.CreateRequest("/Service.svc").And(msg => msg.Content = content).PostAsync().Result) + { + res.EnsureSuccessStatusCode(); + } + } + } + [TestMethod] public void Soap12PingWithActionInEnvelopeHeader() { @@ -253,8 +303,8 @@ public async Task Soap12DetailedFault() ExceptionProperty = "Detail message" }); } - } - + } + [TestMethod] public async Task Soap12InvalidSchema() { diff --git a/src/SoapCore/ParsedMessage.cs b/src/SoapCore/ParsedMessage.cs index ba8159d7..c3695fb6 100644 --- a/src/SoapCore/ParsedMessage.cs +++ b/src/SoapCore/ParsedMessage.cs @@ -188,9 +188,12 @@ private static (XDocument, bool isEmpty) ExtractSoapBody(XDocument envelope, Mes return (new XDocument(), true); } - var rootAttributes = root.Attributes(); + // The envelope attributes are carried onto the body so that it keeps its namespace bindings once it is + // detached. An attribute the body already declares has to win: XAttribute does not override equality, so + // Union compares by reference and a declaration present on both elements would be added twice and throw. var bodyAttributes = bodyNode.Attributes(); - var allAttributes = bodyAttributes.Union(rootAttributes); + var rootAttributes = root.Attributes().Where(attribute => bodyNode.Attribute(attribute.Name) == null); + var allAttributes = bodyAttributes.Concat(rootAttributes).ToList(); bodyNode.ReplaceAttributes(allAttributes); //return new XDocument(bodyNode.Elements().FirstOrDefault());