2

2 つのエンドポイントを持つサービスがあります。

<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 クライアントにはデフォルトで 1 つのエンドポイントしかありません。

デフォルトでは、wsdl 定義を取得するためのパスは次のようになります。

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

別の URL で wsdl 定義を提供することは可能でしょうか?:

例えば:

http://[サーバー]:8080/service.svc/basic?wsdl
http://[サーバー]:8080/service.svc/ws?wsdl

IWsdlExportExtension 実装を使用してカスタム エンドポイント動作を実装することで、リクエストに基づいてエンドポイントがエクスポートされないようにすることができます。

これが可能かどうか、私のアプローチが正しいかどうか、または私が完全に間違っているかどうかを知りたいのですが、これができないか、少し複雑すぎます。ありがとう

4

1 に答える 1

1

私の知る限り、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();
    }
}
于 2013-03-15T15:55:47.220 に答える