エンドポイント アドレスの指定
Windows Communication Foundation (WCF) サービスとの通信はすべて、そのエンドポイントを通して行われます。 各 ServiceEndpoint は、Address、Binding、および Contract で構成されます。 コントラクトでは、使用できる操作を指定します。 バインディングでは、サービスとの通信方法を指定し、アドレスでは、サービスの場所を指定します。 各エンドポイントには、一意のアドレスを設定する必要があります。 エンドポイント アドレスは、EndpointAddress クラスによって表します。このクラスは、サービスのアドレスを表す URI (Uniform Resource Identifier)、サービスのセキュリティ ID を表す Identity、およびオプションの Headers のコレクションで構成されます。 オプション ヘッダーは、エンドポイントの識別または対話のために、より詳細なアドレス指定情報を提供します。 たとえば、ヘッダーを使用して、受信メッセージの処理方法や、エンドポイントからの応答メッセージの送信先を指定できるほか、複数のサービス インスタンスが使用できる場合に、特定ユーザーからの受信メッセージの処理に使用するインスタンスを指定できます。
エンドポイント アドレスの定義
WCF の EndpointAddress により、WS-Addressing 仕様で定義されているエンドポイント参照 (EPR) がモデル化されます。
ほとんどのトランスポートの URI アドレスは、4 つの部分から構成されます。 たとえば、http://www.fabrikam.com:322/mathservice.svc/secureEndpoint
という URI には、次の 4 つの部分があります。
スキーム : http:
コンピューター:
www.fabrikam.com
(省略可能) ポート: 322
パス : /mathservice.svc/secureEndpoint
EPR モデルの一部では、各エンドポイント参照は、追加の識別情報を追加する複数の参照パラメーターを伝達できます。 WCF では、これらの参照パラメーターは AddressHeader クラスのインスタンスとしてモデル化されます。
サービスのエンドポイント アドレスはコードを使用して強制的に指定するか、構成を介して宣言として指定できます。 設置済みサービスのバインドおよびアドレスは一般的に、サービスの開発中に使用されるものとは異なるので、コード内でエンドポイントを定義することは通常、実用的ではありません。 一般に、サービス エンドポイントの定義にはコードではなく、構成を使用する方がより実用的です。 バインディング情報とアドレス情報をコードに含めないことで、変更時にアプリケーションの再コンパイルや再展開を行う必要がなくなります。 エンドポイントがコードまたは構成で指定されていない場合、ランタイムは、サービスで実装されたコントラクトごとに、1 つの既定のエンドポイントを各ベース アドレスに追加します。
WCF でサービスのエンドポイント アドレスを指定するには 2 つの方法があります。 サービスに関連付けられた各エンドポイントに対して絶対アドレスを指定する方法と、ServiceHost のベース アドレスを設定して、このベース アドレスから相対的に定義されるアドレスをサービスに関連付けられた各エンドポイントに対して指定する方法です。 サービスのエンドポイント アドレスを指定するには、構成とコードのいずれかで、これらの各方法を使用します。 相対アドレスを指定しない場合、サービスはベース アドレスを使用します。 サービスに対して複数のベース アドレスを設定することもできますが、サービスが各トランスポートに対して設定できるベース アドレスは 1 つに限られます。 複数のエンドポイントがある場合、各エンドポイントには異なるバインディングで構成されるため、それぞれのアドレスは一意になります。 異なるコントラクトで同じバインディングを使用するエンドポイントは同じアドレスを使用できます。
IIS でホストする場合、ユーザーは ServiceHost インスタンスを管理できません。 IIS でホストしているサービスでは、サービスの .svc ファイルで指定されているアドレスが常にベース アドレスになります。 そのため、IIS でホストされるサービスのエンドポイントでは、相対エンドポイント アドレスを使用する必要があります。 完全修飾されたエンドポイント アドレスを指定すると、サービスの展開時にエラーとなる可能性があります。 詳細については、「インターネット インフォメーション サービスでホストされる WCF サービスの配置」を参照してください。
構成によるエンドポイント アドレスの定義
構成ファイルでエンドポイントを定義するには、<endpoint> 要素を使用します。
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Open メソッドが呼び出されるとき (つまり、ホスト アプリケーションがサービスを開始しようとしたとき)、システムにより、"UE.Samples.HelloService" を指定する name 属性を持つ <service> 要素が検索されます。 その <service> 要素が見つかった場合、システムにより、構成ファイルにあるエンドポイント定義を使用して、指定されたクラスが読み込まれ、エンドポイントが作成されます。 このしくみによって、2 行のコードでサービスを読み込んで開始でき、バインディングとアドレス指定情報をコード外に維持することができます。 この方法の利点は、アプリケーションを再度コンパイルしたり、展開したりすることなく、この 2 つの情報を変更できる点です。
オプション ヘッダーは <headers> で宣言されています。 次に示す例では、構成ファイルでサービスのエンドポイントを指定するための要素で、2 つのヘッダー (http://tempuri1.org/
からの "Gold" クライアントと http://tempuri2.org/
からの "Standard" クライアント) が識別されています。 このサービスを呼び出すクライアントの構成ファイルには、適切な <headers> が記述されている必要があります。
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri1.org/">Gold</Member>
</headers>
</endpoint>
<endpoint address="/Address2"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri2.org/">Silver</Member>
</headers>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
ヘッダーは、(上記のように) エンドポイントのすべてのメッセージに対してではなく、個別のメッセージに設定できます。 この設定は、次の例で示すように、OperationContextScope を使用してクライアント アプリケーションに新しいコンテキストを作成し、送信メッセージにカスタム ヘッダーを追加することで行います。
SampleServiceClient wcfClient = new SampleServiceClient(new InstanceContext(this));
try
{
using (OperationContextScope scope = new OperationContextScope(wcfClient.InnerChannel))
{
MessageHeader header
= MessageHeader.CreateHeader(
"Service-Bound-CustomHeader",
"http://Microsoft.WCF.Documentation",
"Custom Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
//Console.ReadLine();
header = MessageHeader.CreateHeader(
"Service-Bound-OneWayHeader",
"http://Microsoft.WCF.Documentation",
"Different Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// One-way
wcfClient.Push(greeting);
this.wait.WaitOne();
// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
Console.ReadLine();
}
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
Dim wcfClient As New SampleServiceClient(New InstanceContext(Me))
Try
Using scope As New OperationContextScope(wcfClient.InnerChannel)
Dim header As MessageHeader = MessageHeader.CreateHeader("Service-Bound-CustomHeader", _
"http://Microsoft.WCF.Documentation", "Custom Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()
'Console.ReadLine();
header = MessageHeader.CreateHeader("Service-Bound-OneWayHeader", _
"http://Microsoft.WCF.Documentation", "Different Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' One-way
wcfClient.Push(greeting)
Me.wait.WaitOne()
' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
Console.ReadLine()
End Using
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
Console.ReadLine()
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message)
Console.ReadLine()
wcfClient.Abort()
End Try
メタデータ内のエンドポイント アドレス
Web サービス記述言語 (WSDL) では、エンドポイント アドレスは、対応するエンドポイントの EndpointReference
要素内で WS-Addressing の wsdl:port
(EPR) 要素として表されます。 EPR には、エンドポイントのアドレスのほかに、アドレスのすべてのプロパティが含まれます。 wsdl:port
内にある EPR では、次の例に示すように soap:Address
を置き換えるので注意してください。
コードによるエンドポイント アドレスの定義
エンドポイント アドレスは、コードで EndpointAddress クラスを使用して作成できます。 エンドポイント アドレスに指定する URI は、完全修飾パスまたはサービスのベース アドレスを基準にしたパスです。 EndpointAddress クラスのインスタンスを作成し、そのインスタンスを、サービスをホストする ServiceHost インスタンスに追加する方法を次のコードに示します。
次の例は、コードで完全なエンドポイント アドレスを指定する方法を示しています。
Uri baseAddress = new Uri("http://localhost:8000/HelloService");
string address = "http://localhost:8000/HelloService/MyService";
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), address);
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
次の例は、サービス ホストのベース アドレスに相対アドレス ("MyService") を追加する方法を示しています。
Uri baseAddress = new Uri("http://localhost:8000/HelloService");
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), "MyService");
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
Note
ServiceDescription の OnOpening メソッドの後で、サービス アプリケーションの ServiceHostBase の各プロパティを変更しないでください。 このメソッドの後で変更すると、Credentials および AddServiceEndpoint
の ServiceHostBase プロパティや ServiceHost メソッドなどの一部のメンバーは例外をスローします。 変更を許可するメンバーもありますが、結果は未定義の状態になります。
同様に、クライアントで、ServiceEndpoint の OnOpening 呼び出しの後で、ChannelFactory 値を変更しないでください。 この呼び出しの後で変更すると、Credentials プロパティは例外をスローします。 その他のクライアント記述値は、エラーを発生させずに変更できますが、結果は未定義の状態になります。
サービスとクライアントのどちらの場合も、Open の呼び出しの前に記述を変更することをお勧めします。
既定のエンドポイントの使用
エンドポイントがコードまたは構成で指定されていない場合、ランタイムは、サービスで実装されたサービス コントラクトごとに、1 つの既定のエンドポイントを各ベース アドレスに追加することで、既定のエンドポイントを提供します。 ベース アドレスはコードまたは構成で指定することができ、既定のエンドポイントは、Open が ServiceHost で呼び出されるときに追加されます。
エンドポイントを明示的に指定しない場合、AddDefaultEndpoints を呼び出す前に、ServiceHost で Open を呼び出すことによって、既定のエンドポイントを引き続き追加できます。 既定のエンドポイントについては、「Simplified Configuration」 (簡易構成) と「Simplified Configuration for WCF Services」 (WCF サービスの簡易構成) を参照してください。