diff --git a/src/SoapCore.Tests/MessageContract/RawRequestSoap11And12.cs b/src/SoapCore.Tests/MessageContract/RawRequestSoap11And12.cs new file mode 100644 index 00000000..c24ce317 --- /dev/null +++ b/src/SoapCore.Tests/MessageContract/RawRequestSoap11And12.cs @@ -0,0 +1,42 @@ +using System; +using System.Drawing; +using System.Linq; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SoapCore.Tests.MessageContract.Models; + +namespace SoapCore.Tests.MessageContract +{ + [TestClass] + public class RawRequestSoap11And12 + { + [TestMethod] + public async Task Soap11And12MessageContractGetWSDL_ShouldContainSoap11AndSoap12Namespaces() + { + using var host = CreateTestHost(typeof(TestService)); + using var client = host.CreateClient(); + using var res = host.CreateRequest("/Service11And12.asmx?wsdl").GetAsync().Result; + + res.EnsureSuccessStatusCode(); + + var response = await res.Content.ReadAsStringAsync(); + var root = XDocument.Parse(response); + Assert.AreEqual("http://schemas.xmlsoap.org/wsdl/soap/", root.Root.Attributes().FirstOrDefault(t => t.Name.LocalName == "soap").Value); + Assert.AreEqual("http://schemas.xmlsoap.org/wsdl/soap12/", root.Root.Attributes().FirstOrDefault(t => t.Name.LocalName == "soap12").Value); + } + + private TestServer CreateTestHost(Type serviceType) + { + var webHostBuilder = new WebHostBuilder() + .UseStartup() + .ConfigureServices(services => services.AddSingleton(new StartupConfiguration(serviceType))); + return new TestServer(webHostBuilder); + } + } +} diff --git a/src/SoapCore.Tests/MessageContract/Startup.cs b/src/SoapCore.Tests/MessageContract/Startup.cs index 27d0b08f..f93e013f 100644 --- a/src/SoapCore.Tests/MessageContract/Startup.cs +++ b/src/SoapCore.Tests/MessageContract/Startup.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ServiceModel; using System.ServiceModel.Channels; +using System.Text; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; @@ -44,6 +45,33 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF { x.UseSoapEndpoint(_serviceType, "/Service.svc", new SoapEncoderOptions(), SoapSerializer.DataContractSerializer); x.UseSoapEndpoint(_serviceType, "/Service.asmx", new SoapEncoderOptions(), SoapSerializer.XmlSerializer); + + x.UseSoapEndpoint(_serviceType, opt => + { + opt.Path = "/Service11And12.asmx"; + opt.SoapSerializer = SoapSerializer.XmlSerializer; + opt.CaseInsensitivePath = true; + + opt.EncoderOptions = + [ + new SoapEncoderOptions + { + BindingName = "Soap11", + PortName = "Soap11", + WriteEncoding = Encoding.UTF8, + MessageVersion = MessageVersion.Soap11WSAddressingAugust2004, + }, + new SoapEncoderOptions + { + BindingName = "Soap12", + PortName = "Soap12", + WriteEncoding = Encoding.UTF8, + MessageVersion = MessageVersion.Soap12WSAddressingAugust2004, + } + + ]; + }); + x.UseSoapEndpoint(_serviceType, opt => { opt.Path = "/ServiceWithAdditionalEnvelopeXmlnsAttributes.asmx"; diff --git a/src/SoapCore.Tests/SoapCore.Tests.csproj b/src/SoapCore.Tests/SoapCore.Tests.csproj index b965353e..ebb13791 100644 --- a/src/SoapCore.Tests/SoapCore.Tests.csproj +++ b/src/SoapCore.Tests/SoapCore.Tests.csproj @@ -6,6 +6,7 @@ false true + latest diff --git a/src/SoapCore.Tests/Wsdl/WsdlTests.cs b/src/SoapCore.Tests/Wsdl/WsdlTests.cs index 0edf9a9f..4c12bb69 100644 --- a/src/SoapCore.Tests/Wsdl/WsdlTests.cs +++ b/src/SoapCore.Tests/Wsdl/WsdlTests.cs @@ -1183,7 +1183,13 @@ private async Task GetWsdlFromMetaBodyWriter(SoapSerializer serialize : new MetaBodyWriter(service, baseUrl, xmlNamespaceManager, defaultBindingName, new[] { new SoapBindingInfo(MessageVersion.None, bindingName, portName) }, useMicrosoftGuid) as BodyWriter; var encoder = new SoapMessageEncoder(MessageVersion.Soap12WSAddressingAugust2004, Encoding.UTF8, false, XmlDictionaryReaderQuotas.Max, false, false, null, bindingName, portName, true); var responseMessage = Message.CreateMessage(encoder.MessageVersion, null, bodyWriter); - responseMessage = new MetaMessage(responseMessage, service, xmlNamespaceManager, defaultBindingName, false); + responseMessage = new MetaMessage( + responseMessage, + service, + xmlNamespaceManager, + defaultBindingName, + false, + [responseMessage.Version]); var memoryStream = new MemoryStream(); await encoder.WriteMessageAsync(responseMessage, null, memoryStream, true); diff --git a/src/SoapCore/Meta/MetaMessage.cs b/src/SoapCore/Meta/MetaMessage.cs index b49e0b8c..70f06bb5 100644 --- a/src/SoapCore/Meta/MetaMessage.cs +++ b/src/SoapCore/Meta/MetaMessage.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.ServiceModel.Channels; using System.Xml; using SoapCore.ServiceModel; @@ -12,20 +13,23 @@ public class MetaMessage : Message private readonly XmlNamespaceManager _xmlNamespaceManager; private readonly string _bindingName; private readonly bool _hasBasicAuthentication; + private readonly MessageVersion[] _soapVersions; [Obsolete] public MetaMessage(Message message, ServiceDescription service, Binding binding, XmlNamespaceManager xmlNamespaceManager) - : this(message, service, xmlNamespaceManager, binding?.Name, binding.HasBasicAuth()) + : this(message, service, xmlNamespaceManager, binding?.Name, binding.HasBasicAuth(), [message.Version]) { } - public MetaMessage(Message message, ServiceDescription service, XmlNamespaceManager xmlNamespaceManager, string bindingName, bool hasBasicAuthentication) + public MetaMessage(Message message, ServiceDescription service, XmlNamespaceManager xmlNamespaceManager, + string bindingName, bool hasBasicAuthentication, MessageVersion[] soapVersions) { _xmlNamespaceManager = xmlNamespaceManager; _message = message; _service = service; _bindingName = bindingName; _hasBasicAuthentication = hasBasicAuthentication; + _soapVersions = soapVersions; } public override MessageHeaders Headers => _message.Headers; @@ -42,18 +46,22 @@ protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer) { writer.WriteStartElement(_xmlNamespaceManager.LookupPrefix(Namespaces.WSDL_NS), "definitions", Namespaces.WSDL_NS); - // Soap11 - if (Version == MessageVersion.Soap11 || Version == MessageVersion.Soap11WSAddressingAugust2004 || Version == MessageVersion.Soap11WSAddressingAugust2004) + var wroteSoapNamespace = false; + if (_soapVersions.Contains(MessageVersion.Soap11) || + _soapVersions.Contains(MessageVersion.Soap11WSAddressingAugust2004)) { WriteXmlnsAttribute(writer, Namespaces.SOAP11_NS); + wroteSoapNamespace = true; } - // Soap12 - else if (Version == MessageVersion.Soap12WSAddressing10 || Version == MessageVersion.Soap12WSAddressingAugust2004) + if (_soapVersions.Contains(MessageVersion.Soap12WSAddressing10) || + _soapVersions.Contains(MessageVersion.Soap12WSAddressingAugust2004)) { WriteXmlnsAttribute(writer, Namespaces.SOAP12_NS); + wroteSoapNamespace = true; } - else + + if(!wroteSoapNamespace) { throw new ArgumentOutOfRangeException(nameof(Version), "Unsupported MessageVersion encountered while writing envelope."); } diff --git a/src/SoapCore/SoapEndpointMiddleware.cs b/src/SoapCore/SoapEndpointMiddleware.cs index ea2a9513..26485ade 100644 --- a/src/SoapCore/SoapEndpointMiddleware.cs +++ b/src/SoapCore/SoapEndpointMiddleware.cs @@ -249,13 +249,15 @@ private async Task ProcessMeta(HttpContext httpContext, bool showDocumentation) //assumption that you want soap12 if your service supports that var messageEncoder = _messageEncoders.FirstOrDefault(me => me.MessageVersion == MessageVersion.Soap12WSAddressing10 || me.MessageVersion == MessageVersion.Soap12WSAddressingAugust2004) ?? _messageEncoders[0]; + var soapVersions = _messageEncoders.Select(me => me.MessageVersion).Distinct().ToArray(); using var responseMessage = new MetaMessage( Message.CreateMessage(messageEncoder.MessageVersion, null, bodyWriter), _service, GetXmlNamespaceManager(messageEncoder), bindingName, - _options.UseBasicAuthentication); + _options.UseBasicAuthentication, + soapVersions); if (showDocumentation) {