エンドポイント アドレスの指定
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> elementで宣言します。次に示す例では、構成ファイルでサービスのエンドポイントを指定するための要素で、2 つのヘッダー (http://tempuri1.org/ からの "Gold" クライアントと http://tempuri2.org/ からの "Standard" クライアント) を識別しています。このサービスを呼び出すクライアントの構成ファイルには、適切な <headers> elementが記述されている必要があります。
<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 を使用してクライアント アプリケーションに新しいコンテキストを作成し、送信メッセージにカスタム ヘッダーを追加することで行います。
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
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();
}
メタデータ内のエンドポイント アドレス
Web サービス記述言語 (WSDL) では、エンドポイント アドレスは、対応するエンドポイントの wsdl:port 要素内で WS-Addressing の EndpointReference (EPR) 要素として表されます。EPR には、エンドポイントのアドレスのほかに、アドレスのすべてのプロパティが含まれます。wsdl:port 内にある EPR では、次の例に示すように soap:Address を置き換えるので注意してください。
コードによるエンドポイント アドレスの定義
エンドポイント アドレスは、コードで EndpointAddress クラスを使用して作成できます。エンドポイント アドレスに指定する URI は、完全修飾パスまたはサービスのベース アドレスを基準にしたパスです。EndpointAddress クラスのインスタンスを作成し、そのインスタンスを、サービスをホストする ServiceHost インスタンスに追加する方法を次のコードに示します。
次の例は、コードで完全なエンドポイント アドレスを指定する方法を示しています。
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
string address = "https://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("https://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();
}
注 : |
---|
ServiceHostBase の OnOpening メソッドの後で、サービス アプリケーションの ServiceDescription の各プロパティを変更しないでください。このメソッドの後で変更すると、ServiceHostBase および ServiceHost の Credentials プロパティや AddServiceEndpoint メソッドなどの一部のメンバーは例外をスローします。変更を許可するメンバーもありますが、結果は未定義の状態になります。 同様に、クライアントで、ChannelFactory の OnOpening 呼び出しの後で、ServiceEndpoint 値を変更しないでください。この呼び出しの後で変更すると、Credentials プロパティは例外をスローします。その他のクライアント記述値は、エラーを発生させずに変更できますが、結果は未定義の状態になります。 サービスとクライアントのどちらの場合も、Open の呼び出しの前に記述を変更することをお勧めします。 |
既定のエンドポイントの使用
エンドポイントがコードまたは構成で指定されていない場合、ランタイムは、サービスで実装されたサービス コントラクトごとに、1 つの既定のエンドポイントを各ベース アドレスに追加することで、既定のエンドポイントを提供します。ベース アドレスはコードまたは構成で指定することができ、既定のエンドポイントは、Open が ServiceHost で呼び出されるときに追加されます。
エンドポイントを明示的に指定しない場合、Open を呼び出す前に、ServiceHost の AddDefaultEndpoints を呼び出すことによって、既定のエンドポイントを引き続き追加できます。既定のエンドポイント、バインディング、および動作詳細情報、「簡略化された構成」および「WCF サービスの簡略化された構成」を参照してください。