【问题标题】:How can I add a namespace to soap envelope in c#如何在 C# 中将命名空间添加到肥皂信封
【发布时间】:2018-12-10 13:19:10
【问题描述】:

我想在我的肥皂信封中添加一个命名空间设置。 我想在 IClientMessageInspector 的 BeforeSendRequest 中更改它,或者您有更优雅的方式。

例如

<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>

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

请帮帮我!

谢谢!

【问题讨论】:

    标签: c# wcf soap namespaces client


    【解决方案1】:

    根据您的描述,我认为您可以使用 WCF 消息检查器。在客户端发送消息之前。我们可以自定义消息正文。
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/message-inspectors
    我做了一个demo,希望对你有用。
    服务器端。

    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;
            }
    
    }
    

    客户。

    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;
            }
    }  
    

    不要忘记将 CustContract 行为应用到服务接口。

        [CustContractBehavior]
    public interface ICalculator {
    

    结果。

    【讨论】:

    • 非常感谢!这是我喜欢的方式。一件事 - 我无法访问服务本身。我只开发客户端。
    • 只需要将该属性应用到客户端添加引用生成的服务接口即可。上面的服务器端代码只是模拟了一个 WCF 服务,所以我可以做一个演示。
    【解决方案2】:

    我通常这样使用xml linq

    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();
    
    
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      有一种更好的方法可以在 WCF 中向 SOAP 消息添加名称空间或前缀。使用自定义 MessageFormatter。看看这些文章: 对于客户端 https://weblog.west-wind.com/posts/2016/apr/02/custom-message-formatting-in-wcf-to-add-all-namespaces-to-the-soap-envelope#ClientMessageFormatter

      服务端 https://www.vanacosmin.ro/Articles/Read/WCFEnvelopeNamespacePrefix

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多