【问题标题】:WCF Service WSDL definition with selective endpoints by implementing IWsdlExporteExtension通过实现 IWsdlExporteExtension 具有选择性端点的 WCF 服务 WSDL 定义
【发布时间】:2013-03-15 13:48:21
【问题描述】:

我有一个有两个端点的服务:

<service name="WcfService4.Service1">
    <endpoint bindingConfiguration="myBinding"
              contract="WcfService4.IService1"
              binding="basicHttpBinding">
    </endpoint>
    <endpoint name="wsEndpoint"
              contract="WcfService4.IService1"
              binding="wsHttpBinding">
    </endpoint>
<service>

此服务将由 Framework 2.0 和 4.0 客户端使用。从 2.0 客户端添加 Web 服务引用时一切正常。当我从 4.0 客户端添加服务引用时,会创建两个端点,使客户端指定它要使用的端点。

我想要实现的是让用户可以选择下载:服务的 basicHttpBinding 端点或 wsHttpBinding 端点,但不能同时下载,因此框架 4.0 客户端默认只有一个端点。

默认情况下,检索 wsdl 定义的路径是:

http://[server]:8080/MyApp/service.svc?wsdl

是否可以在另一个 url 上提供 wsdl 定义?:

例如:

http://[服务器]:8080/service.svc/basic?wsdl
http://[服务器]:8080/service.svc/ws?wsdl

通过使用 IWsdlExportExtension 实现来实现自定义端点行为,我可能会根据请求隐藏端点以防止被导出。

我想知道这是否可能,我的方法是否正确,或者我是否完全错误,或者无法做到这一点,因为我让事情变得有点复杂。谢谢

【问题讨论】:

    标签: c# vb.net wcf


    【解决方案1】:

    AFAIK 在 WSDL 导出扩展上,您没有收到发起 WSDL 创建过程的请求。但是您可以通过使用非 SOAP(也称为 REST)端点来公开 WSDL 来做到这一点。在此示例中,它只是向服务本身发送一个 HTTP 请求以获取 WSDL,然后“修剪”未请求的端点的结果 WSDL (XML)。

    运行这段代码后,如果你运行

    svcutil http://localhost:8000/service/conditionalwsdl/getwsdl?endpoint=basic
    

    你只会得到BasicHttpBinding的端点,而如果你运行

    svcutil http://localhost:8000/service/conditionalwsdl/getwsdl?endpoint=ws
    

    您只能通过WSHttpBinding 获得端点。

    public class StackOverflow_15434117
    {
        [ServiceContract]
        public interface ITest
        {
            [OperationContract]
            string Echo(string text);
        }
        [ServiceContract]
        public interface IConditionalMetadata
        {
            [WebGet]
            XmlElement GetWSDL(string endpoint);
        }
        public class Service : ITest, IConditionalMetadata
        {
            public string Echo(string text)
            {
                return text;
            }
    
            public XmlElement GetWSDL(string endpoint)
            {
                WebClient c = new WebClient();
                string baseAddress = OperationContext.Current.Host.BaseAddresses[0].ToString();
                byte[] existingMetadata = c.DownloadData(baseAddress + "?wsdl");
                XmlDocument doc = new XmlDocument();
                doc.Load(new MemoryStream(existingMetadata));
                XmlElement result = doc.DocumentElement;
                XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
                nsManager.AddNamespace("wsdl", "http://schemas.xmlsoap.org/wsdl/");
                nsManager.AddNamespace("soap11", "http://schemas.xmlsoap.org/wsdl/soap/");
                nsManager.AddNamespace("soap12", "http://schemas.xmlsoap.org/wsdl/soap12/");
    
                List<XmlNode> toRemove = new List<XmlNode>();
    
                // Remove all SOAP 1.1 endpoints which are not the requested one
                XmlNodeList toRemove11 = result.SelectNodes("//wsdl:service/wsdl:port/soap11:address", nsManager);
                XmlNodeList toRemove12 = result.SelectNodes("//wsdl:service/wsdl:port/soap12:address", nsManager);
                foreach (XmlNode node in toRemove11)
                {
                    if (!node.Attributes["location"].Value.EndsWith(endpoint, StringComparison.OrdinalIgnoreCase))
                    {
                        toRemove.Add(node);
                    }
                }
    
                foreach (XmlNode node in toRemove12)
                {
                    if (!node.Attributes["location"].Value.EndsWith(endpoint, StringComparison.OrdinalIgnoreCase))
                    {
                        toRemove.Add(node);
                    }
                }
    
                List<string> bindingsToRemove = new List<string>();
                foreach (XmlNode node in toRemove)
                {
                    string binding;
                    RemoveWsdlPort(node, out binding);
                    bindingsToRemove.Add(binding);
                }
    
                toRemove.Clear();
                foreach (var binding in bindingsToRemove)
                {
                    string[] parts = binding.Split(':');
                    foreach (XmlNode node in result.SelectNodes("//wsdl:binding[@name='" + parts[1] + "']", nsManager))
                    {
                        toRemove.Add(node);
                    }
                }
    
                foreach (XmlNode bindingNode in toRemove)
                {
                    bindingNode.ParentNode.RemoveChild(bindingNode);
                }
    
                return result;
            }
    
            static void RemoveWsdlPort(XmlNode wsdlPortDescendant, out string binding)
            {
                while (wsdlPortDescendant.LocalName != "port" && wsdlPortDescendant.NamespaceURI != "http://schemas.xmlsoap.org/wsdl/")
                {
                    wsdlPortDescendant = wsdlPortDescendant.ParentNode;
                }
    
                binding = wsdlPortDescendant.Attributes["binding"].Value;
    
                var removed = wsdlPortDescendant.ParentNode.RemoveChild(wsdlPortDescendant);
            }
        }
        public static void Test()
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "basic");
            host.AddServiceEndpoint(typeof(ITest), new WSHttpBinding(), "ws");
            host.AddServiceEndpoint(typeof(IConditionalMetadata), new WebHttpBinding(), "conditionalWsdl")
                .Behaviors.Add(new WebHttpBehavior());
            host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
            host.Open();
            Console.WriteLine("Host opened");
    
            ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress + "/basic"));
            ITest proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Echo("Hello"));
    
            ((IClientChannel)proxy).Close();
            factory.Close();
    
            Console.WriteLine("Press ENTER to close the host");
            Console.ReadLine();
            host.Close();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 1970-01-01
      • 2011-11-26
      • 2010-10-18
      • 1970-01-01
      相关资源
      最近更新 更多