Specifying an Endpoint Address

Definition of an Endpoint Address

In WCF, an EndpointAddress models an endpoint reference (EPR) as defined in the WS-Addressing standard.

The address URI for most transports has four parts. For example, this URI, http://www.fabrikam.com:322/mathservice.svc/secureEndpoint has the following four parts:

• Scheme: http:

• Machine: www.fabrikam.com

• (Optional) Port: 322

• Path: /mathservice.svc/secureEndpoint

Part of the EPR model is that each endpoint reference can carry some reference parameters that add extra identifying information. In WCF, these reference parameters are modeled as instances of the AddressHeader class.

The endpoint address for a service can be specified either imperatively by using code or declaratively through configuration. Defining endpoints in code is usually not practical because the bindings and addresses for a deployed service are typically different from those used while the service is being developed. Generally, it is more practical to define service endpoints using configuration rather than code. Keeping the binding and addressing information out of the code allows them to change without having to recompile and redeploy the application. If no endpoints are specified in code or in configuration, then the runtime adds one default endpoint on each base address for each contract implemented by the service.

When hosting with IIS, you do not manage the ServiceHost instance yourself. The base address is always the address specified in the .svc file for the service when hosting in IIS. So you must use relative endpoint addresses for IIS-hosted service endpoints. Supplying a fully-qualified endpoint address can lead to errors in the deployment of the service. For more information, see Deploying an Internet Information Services-Hosted WCF Service.

Defining Endpoint Addresses in Configuration

To define an endpoint in a configuration file, use the <endpoint> element.

<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
binding="basicHttpBinding"
contract="UE.Samples.IHello"/>

binding="mexHttpBinding"
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>


When the Open method is called (that is, when the hosting application attempts to start the service), the system looks for a <service> element with a name attribute that specifies "UE.Samples.HelloService". If the <service> element is found, the system loads the specified class and creates endpoints using the endpoint definitions provided in the configuration file. This mechanism allows you to load and start a service with two lines of code while keeping binding and addressing information out of your code. The advantage of this approach is that these changes can be made without having to recompile or redeploy the application.

The optional headers are declared in a <headers>. The following is an example of the elements used to specify endpoints for a service in a configuration file that distinguishes between two headers: "Gold" clients from http://tempuri1.org/ and "Standard" clients from http://tempuri2.org/. The client calling this service must have the appropriate <headers> in its configuration file.

<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<Member xmlns="http://tempuri1.org/">Gold</Member>
</endpoint>
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<Member xmlns="http://tempuri2.org/">Silver</Member>
</endpoint>

binding="mexHttpBinding"
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>


Headers can also be set on individual messages instead of all messages on an endpoint (as shown previously). This is done by using OperationContextScope to create a new context in a client application to add a custom header to the outgoing message, as shown in the following example.

SampleServiceClient wcfClient = new SampleServiceClient(new InstanceContext(this));
try
{
using (OperationContextScope scope = new OperationContextScope(wcfClient.InnerChannel))
{
"http://Microsoft.WCF.Documentation",
"Custom Happy Value."
);

// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();

"http://Microsoft.WCF.Documentation",
"Different Happy Value."
);

// One-way
wcfClient.Push(greeting);
this.wait.WaitOne();

// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
}
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message);
wcfClient.Abort();
}

Dim wcfClient As New SampleServiceClient(New InstanceContext(Me))
Try
Using scope As New OperationContextScope(wcfClient.InnerChannel)
"http://Microsoft.WCF.Documentation", "Custom Happy Value.")

' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()

"http://Microsoft.WCF.Documentation", "Different Happy Value.")

' One-way
wcfClient.Push(greeting)
Me.wait.WaitOne()

' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
End Using
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message)
wcfClient.Abort()
End Try


An endpoint address is represented in Web Services Description Language (WSDL) as a WS-Addressing EndpointReference (EPR) element inside the corresponding endpoint's wsdl:port element. The EPR contains the endpoint's address as well as any address properties. Note that the EPR inside wsdl:port replaces soap:Address as seen in the following example.

Defining Endpoint Addresses in Code

An endpoint address can be created in code with the EndpointAddress class. The URI specified for the endpoint address can be a fully-qualified path or a path that is relative to the service's base address. The following code illustrates how to create an instance of the EndpointAddress class and add it to the ServiceHost instance that is hosting the service.

The following example demonstrates how to specify the full endpoint address in code.

Uri baseAddress = new Uri("http://localhost:8000/HelloService");
string address = "http://localhost:8000/HelloService/MyService";

using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
serviceHost.Close();
}


The following example demonstrates how to add a relative address ("MyService") to the base address of the service host.

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");
serviceHost.Close();
}


Note

Properties of the ServiceDescription in the service application must not be modified subsequent to the OnOpening method on ServiceHostBase. Some members, such as the Credentials property and the AddServiceEndpoint methods on ServiceHostBase and ServiceHost, throw an exception if modified after that point. Others permit you to modify them, but the result is undefined.

Similarly, on the client the ServiceEndpoint values must not be modified after the call to OnOpening on the ChannelFactory. The Credentials property throws an exception if modified after that point. The other client description values can be modified without error, but the result is undefined.

Whether for the service or client, it is recommended that you modify the description prior to calling Open.

Using Default Endpoints

If no endpoints are specified in code or in configuration then the runtime provides default endpoints by adding one default endpoint on each base address for each service contract implemented by the service. The base address can be specified in code or in configuration, and the default endpoints are added when Open is called on the ServiceHost.

If endpoints are explicitly provided, the default endpoints can still be added by calling AddDefaultEndpoints on the ServiceHost before calling Open. For more information about default endpoints, bindings, and behaviors, see Simplified Configuration and Simplified Configuration for WCF Services.