WCF ~ メタデータのエクスポートとプロキシコードの生成
これまで WCF を用いて SOAP メッセージの受け渡しができることを見てきました。 しかし、そのインターフェイス定義が何らかの形で外部に公開され、それがクライアントから利用可能になって初めて、 オープンなプロトコルで通信している意味が深まるというものです。
WCF では WS-Metadata Exchange にて記述された方法でインターフェイス定義を公開します。Web サービスの定義 (型、メソッド等の定義) やエンドポイント (接続可能なデータポートとプロトコル等) を含め、それをメタデータといいます。
メタデータの公開
デフォルトでは、メタデータは外部に公開されません。メタデータを公開するには、以下のように ServiceMetadataBehavior や MetadataExchangeBindings を利用します。詳しくは MSDN をご覧ください。 ここでは実装例を示します。
HelloWCFReceiverApp.cs を以下のように書き換えます。
using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; sealed class HelloWCFReceiverApp { static void Main() { ServiceHost svc = new ServiceHost( typeof(HelloWCF) ); // 基本のサービス Uri address = new Uri ( "http://localhost:4000/IHelloWCF" ); BasicHttpBinding binding = new BasicHttpBinding(); svc.AddServiceEndpoint( typeof(IHelloWCF), binding, address ); // メタデータの公開 ServiceMetadataBehavior md = new ServiceMetadataBehavior(); svc.Description.Behaviors.Add(md); Binding meb = MetadataExchangeBindings.CreateMexTcpBinding(); Uri mebaddr = new Uri ( "net.tcp://localhost:4001/IHelloWCF/Mex" ); svc.AddServiceEndpoint( typeof(IMetadataExchange), meb, mebaddr ); svc.Open(); Console.WriteLine ( "HelloWCFReceiverApp: Wainting for messages..." ); Console.ReadLine(); svc.Close(); } }
ビルド方法等は以前と同様です。
プロキシコードの生成
プロキシコードは、svcutil コマンドで生成できます。
/out オプションに出力するファイル名を指定します。/target オプションについては、 プロキシコードを生成する場合は code を指定します。
> svcutil /out:HelloWCFProxy.cs /target:code net.tcp://localhost:4001/IHelloWCF/Mex Microsoft (R) Service Model Metadata Tool [Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.648] Copyright (c) Microsoft Corporation. All rights reserved. Attempting to download metadata from 'net.tcp://localhost:4001/IHelloWCF/Mex' using WS-Metadata Exchange. This URL does not support DISCO. Generating files... C:\tmp\HelloWCFProxy.cs C:\tmp\output.config >
上記で、HelloWCFProxy.cs と output.config が生成されました。
一応、上で生成されたソースを確認します。HelloWCFProxy.cs です。
//------------------------------------------------------------------------------ //// This code was generated by a tool. // Runtime Version:2.0.50727.3053 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] [System.ServiceModel.ServiceContractAttribute(ConfigurationName="IHelloWCF")] public interface IHelloWCF { [System.ServiceModel.OperationContractAttribute( Action="http://tempuri.org/IHelloWCF/Say", ReplyAction="http://tempuri.org/IHelloWCF/SayResponse")] void Say(string input); } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public interface IHelloWCFChannel : IHelloWCF, System.ServiceModel.IClientChannel { } [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public partial class HelloWCFClient : System.ServiceModel.ClientBase<IHelloWCF>, IHelloWCF { public HelloWCFClient() { } public HelloWCFClient(string endpointConfigurationName) : base(endpointConfigurationName) { } public HelloWCFClient( string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public HelloWCFClient( string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public HelloWCFClient( System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } public void Say(string input) { base.Channel.Say(input); } }
output.config は次の通り。
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IHelloWCF" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <security mode="None"> <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="http://localhost:4000/IHelloWCF" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IHelloWCF" contract="IHelloWCF" name="BasicHttpBinding_IHelloWCF" /> </client> </system.serviceModel> </configuration>
クライアントプログラムのリビルド
そこで、このプロキシコードと送信プログラムのソースから、新しく送信プログラムをビルドします。
> csc /out:SenderApp.exe HelloWCFProxy.cs HelloWCFSenderApp.cs Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1 for Microsoft (R) .NET Framework version 3.5 Copyright (C) Microsoft Corporation. All rights reserved. >
そこで送信プログラムを実行します。問題なくメッセージが送受信できました。
> SenderApp.exe >