60426

How can I add a namespace to soap envelope in c#

<h3>Question</h3>

I want to add a namespace setting to my soap envelope. I would like to change it in the BeforeSendRequest in an IClientMessageInspector or you have a more elegant way.

For example

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"> <s:Header> <wsa:To xmlns="http://www.w3.org/2005/08/addressing">ws://xxx/V1</wsa:To> ... </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> ... </s:Body> </s:Envelope>

to

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing"> ...

please help me!

Thank you!


<h3>Answer1:</h3>

According to your description, I think you could use WCF Message Inspector. Before the client send the message. We could customize the message body.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/message-inspectors
I have made a demo, wish it is useful to you.
Server end.

class Program { static void Main(string[] args) { Uri uri = new Uri("http://localhost:1500"); BasicHttpBinding binding = new BasicHttpBinding(); binding.TransferMode = TransferMode.Buffered; binding.Security.Mode = BasicHttpSecurityMode.None; ServiceHost sh = new ServiceHost(typeof(Calculator),uri); sh.AddServiceEndpoint(typeof(ICalculator), binding, ""); ServiceMetadataBehavior smb; smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (smb == null) { smb = new ServiceMetadataBehavior(); //smb.HttpGetEnabled = true; sh.Description.Behaviors.Add(smb); } Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding(); sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "MEX"); sh.Open(); Console.Write("Service is ready...."); Console.ReadLine(); sh.Close(); } } [ServiceContract] public interface ICalculator { [OperationContract,WebGet] double Add(double a, double b); } public class Calculator : ICalculator { public double Add(double a, double b) { return a + b; } }

Client.

class Program { static void Main(string[] args) { ServiceReference2.CalculatorClient client = new ServiceReference2.CalculatorClient(); try { var result = client.Add(34, 20); Console.WriteLine(result); } catch (Exception) { throw; } } } public class ClientMessageLogger : IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { string result = $"server reply message:\n{reply}\n"; Console.WriteLine(result); } public object BeforeSendRequest(ref Message request, IClientChannel channel) { XmlDocument doc = new XmlDocument(); MemoryStream ms = new MemoryStream(); XmlWriter writer = XmlWriter.Create(ms); request.WriteMessage(writer); writer.Flush(); ms.Position = 0; doc.Load(ms); ChangeMessage(doc); ms.SetLength(0); writer = XmlWriter.Create(ms); doc.WriteTo(writer); writer.Flush(); ms.Position = 0; XmlReader reader = XmlReader.Create(ms); request = System.ServiceModel.Channels.Message.CreateMessage(reader, int.MaxValue, request.Version); string result = $"client ready to send message:\n{request}\n"; Console.WriteLine(result); return null; } void ChangeMessage(XmlDocument doc) { XmlElement element = (XmlElement)doc.GetElementsByTagName("s:Envelope").Item(0); if (element != null) { element.SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); element.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); } } } public class CustContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute { public Type TargetContract => typeof(ICalculator); public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { return; } public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger()); } public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { return; } public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { return; } }

Don’t forget apply the CustContractbehavior to the service interface.

[CustContractBehavior] public interface ICalculator {

Result.


<h3>Answer2:</h3>

I usually use xml linq like this

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Xml.Linq; namespace ConsoleApplication91 { class Program { static void Main(string[] args) { string ws = "http://www.w3.org/2005/08/addressing"; string xml = string.Format( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">" + "<s:Header>" + "<wsa:Address xmlns:wsa=\"{0}\">ws://xxx/V1</wsa:Address>" + "</s:Header>" + "<s:Body>" + "</s:Body>" + "</s:Envelope>", ws); XDocument doc = XDocument.Parse(xml); XElement header = doc.Descendants().Where(x => x.Name.LocalName == "Header").FirstOrDefault(); XElement body = doc.Descendants().Where(x => x.Name.LocalName == "Body").FirstOrDefault(); } } }
<h3>Answer3:</h3>

There is a better way to add a namespace or prefix to SOAP message in WCF. Use a custom MessageFormatter. Look at these articles: For client side https://weblog.west-wind.com/posts/2016/apr/02/custom-message-formatting-in-wcf-to-add-all-namespaces-to-the-soap-envelope#ClientMessageFormatter

For service side https://www.vanacosmin.ro/Articles/Read/WCFEnvelopeNamespacePrefix

来源:https://stackoverflow.com/questions/53706539/how-can-i-add-a-namespace-to-soap-envelope-in-c-sharp

Recommend