例としてGetRegionsメソッドを使用したYandex Directサービスの使用(WCFクライアント)

要求への応答で使用される実際のデータスキームは、サービスによって提供されるWSDL記述のスキームと一致しないため、Yandex.DirectはSOAPプロトコルを使用して正しく動作しません。 つまり、名前空間は一致しません(「API」の代わりに「 namespaces.soaplite.com/perl 」と「 xml.apache.org/xml-soap 」が来る)、およびパラメーター名(例えば、「return」という名前の代わりにGetRegionsメソッドで) 「ArrayOfRegionInfo」になります)。



最初の問題を解消するために、サービスからのメッセージの傍受と名前空間の調整が実装されました。

2番目の問題を修正するために、Reference.cs自動生成WSDLファイルが単純に修正されました。

公式には、Yandex.Directサービスは、WCFを使用してC#で開発されたアプリケーションをサポートしていません。

Yandex.Directは、JSONデータストレージ形式と単純なWebClientを使用してサービスと対話する例を提供します。 この例は、SOAPとは異なり、正しく機能しますが、受信したオブジェクトを自分でデシリアライズする必要がある、サービスとクライアント間のコントラクトがサポートされていないなど、多くの欠点があります。



準備する


サービスのドキュメントはここにあります

サービスを使用するには、以下を行う必要があります。

1.登録(ログイン認証パラメーターでの転送用)、

2.クライアントアプリケーションを作成します(認証パラメーターでapplication_idを渡すため)。

3.テストトークンを取得します(トークン認証パラメーターで送信するため)。

4.認証パラメーターロケールで値「ru」を渡すために使用できます。

サービスのドキュメントで詳細を読むことができますが、ここで書き直さないでください。



アプリケーション作成


1. MS Visual Studioで新しいアプリケーションを作成します。

2.サービスに新しいリンクを追加し、wsdl:“ api.direct.yandex.ru/wsdl/v4”、YandexAPIServiceなどの名前空間(または任意)を指定します。

3. Reference.csファイルでは、タイプSystem.Nullable <System.DateTime>はSystem.DateTimeに置き換えられます

4. YandexAPIService.APIPort.GetRegionsメソッドの説明のReference.csファイルで、「return」パラメーター名を「ArrayOfRegionInfo」に置き換えます。

5.サービスからのメッセージがインターセプトされ、「誤った」名前空間が「正しい」名前空間に置き換えられるMessageInspectorを作成します。



using System; using System.IO; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using System.Xml; namespace YandexDirectRegions { // Client message inspector public class YandexDirectMessageInspector : IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { XmlDocument doc = new XmlDocument(); MemoryStream ms = new MemoryStream(); XmlWriter writer = XmlWriter.Create(ms); reply.WriteMessage(writer); writer.Flush(); ms.Position = 0L; doc.Load(ms); foreach (XmlAttribute attr in doc.DocumentElement.Attributes) if (attr.Value == "http://namespaces.soaplite.com/perl" || attr.Value == "http://xml.apache.org/xml-soap") attr.Value = "API"; ms.Position = 0L; ms.SetLength(0); writer = XmlWriter.Create(ms); doc.WriteTo(writer); writer.Flush(); ms.Position = 0L; XmlReader reader = XmlReader.Create(ms); Message newReply = Message.CreateMessage(reader, int.MaxValue, reply.Version); newReply.Properties.CopyProperties(reply.Properties); newReply.Headers.CopyHeadersFrom(reply); reply = newReply; } public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel) { return null; } } // Endpoint behavior public class YandexDirectEndpointBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { // No implementation necessary } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new YandexDirectMessageInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { // No implementation necessary } public void Validate(ServiceEndpoint endpoint) { // No implementation necessary } } // Configuration element public class YandexDirectBehaviorExtension : BehaviorExtensionElement { public override Type BehaviorType { get { return typeof(YandexDirectEndpointBehavior); } } protected override object CreateBehavior() { // Create the endpoint behavior that will insert the message // inspector into the client runtime return new YandexDirectEndpointBehavior(); } } }
      
      







6.構成ファイル[app | web] .configで、エンドポイントを構成します

 <?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="YandexDirectSoapBinding" maxReceivedMessageSize="100000"> <security mode="Transport" /> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="https://soap.direct.yandex.ru/v4/soap/" binding="basicHttpBinding" bindingConfiguration="YandexDirectSoapBinding" contract="YandexAPIService.APIPort" behaviorConfiguration="YandexDirectBehavior" name="APIPort" /> </client> <behaviors> <endpointBehaviors> <behavior name="YandexDirectBehavior"> <YandexDirectBehaviorExtension /> </behavior> </endpointBehaviors> </behaviors> <extensions> <behaviorExtensions> <add name="YandexDirectBehaviorExtension" type="YandexDirectRegions.YandexDirectBehaviorExtension, YandexDirectRegions" /> </behaviorExtensions> </extensions> </system.serviceModel> </configuration>
      
      







7.メソッド呼び出しを実装します

 using System; using System.Linq; using System.ServiceModel; using System.ServiceModel.Channels; using YandexDirectRegions.YandexAPIService; namespace YandexDirectRegions { //     ,       -  / "" public class Region { public int RegionID { get; set; } public int? ParentID { get; set; } public string RegionName { get; set; } } public class UnitOfWork { YandexAPIService.APIPortClient yandexAPIPortClient; #region Singleton private static volatile UnitOfWork instance; private static object syncRoot = new Object(); private UnitOfWork() { yandexAPIPortClient = new YandexAPIService.APIPortClient(); System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; } public static UnitOfWork Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new UnitOfWork(); } } return instance; } } #endregion public Region[] GetRegions(string application_id, string token, string login, string locale) { Region[] regions = null; var applicationIdHeader = MessageHeader.CreateHeader("application_id", "ns", application_id); var tokenHeader = MessageHeader.CreateHeader("token", "ns", token); var loginHeader = MessageHeader.CreateHeader("login", "ns", login); var localeHeader = MessageHeader.CreateHeader("locale", "ns", locale); using (var scope = new OperationContextScope(yandexAPIPortClient.InnerChannel)) { OperationContext.Current.OutgoingMessageHeaders.Add(applicationIdHeader); OperationContext.Current.OutgoingMessageHeaders.Add(tokenHeader); OperationContext.Current.OutgoingMessageHeaders.Add(loginHeader); OperationContext.Current.OutgoingMessageHeaders.Add(localeHeader); var regionsInfo = yandexAPIPortClient.GetRegions(); if (regionsInfo != null) { regions = regionsInfo.Select<RegionInfo, Region>((regionInfo) => { return new Region() { RegionID = regionInfo.RegionID, ParentID = regionInfo.ParentID, RegionName = regionInfo.RegionName }; } ).ToArray(); } } return regions; } } }
      
      






All Articles