通过实现IWsdlExporteExtension,具有选择性端点的WCF服务WSDL定义
本文关键字:端点 WCF 服务 定义 WSDL 选择性 实现 IWsdlExporteExtension | 更新日期: 2023-09-27 18:04:18
我有一个有两个端点的服务:
<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/基本吗?wsdl
http://(服务器):8080/service.svc/ws ? wsdl
通过使用IWsdlExportExtension实现实现自定义端点行为,我可以根据请求隐藏端点而不被导出。
我想知道这是否可能,如果我的方法是正确的,或者如果我完全错了,要么这不能做,要么我把事情弄得太复杂了。由于
在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();
}
}