If you understand EndPoints well, you understand WCF well. Configuring EndPoints are vital for any WCF design. You can configure EndPoints either via code or in a web.config file. I have seen many times, developers are confused by EndPoints. I have come across the following common question about EndPoints:
- Can we have multiple EndPoints?
- Can we expose the same contracts on more than one EndPoint?
- How base address works with EndPoints?
- Can we have more than one base address?
- How to configure EndPoints in code.
- Do we need to configure an EndPoint in self-hosting?
- Can we have more than one service Contract?
And many more questions like the above.
To answer the above questions, let us start by understanding what EndPoints are.
Endpoints identify a WCF Service. An EndPoint is a combination of Address, Contract and Binding. Mathematically an EndPoint can be defined as below:
Where A, B and C are as follows:
Now it is a simple mathematical addition rule that if we change the value of any of A, B or C then we will get a new E. So for any reason if you change either of Address, Contract or Binding then a new EndPoint will be created. You may have multiple EndPoints of the same service.
- If the same service is hosted on multiple addresses with the same Binding and the same Contract
- If the same service with a different Contract on the same Address and for the same Binding
- If the same service with a different Bindings on the same Address and for the same Contract.
We can say that as a service designer you may consider to create multiple EndPoints in the following scenarios.
- Service wants to expose more than one type of binding.
- Service wants to expose more than one contract on the same binding.
- Service wants to expose same binding and contract on different addresses.
Multiple Binding Scenario
Now let us see how to expose a service on two different bindings using multiple EndPoints. For two different bindings, we will create two different EndPoints.
Let us say we have a service as below:
- public interface IService1
- {
- [OperationContract]
- string message(string name);
-
- }
And the service is implemented as below:
- public class Service1 : IService1
- {
- public string message(string name)
- {
- return "Hello " + name;
- }
- }
We can configure multiple EndPoints as:
- <service name="MessagePatternDemo.Service1">
- <endpoint name="ep1"
- address="/ep1"
- binding="basicHttpBinding"
- contract="MessagePatternDemo.IService1"/>
- <endpoint name="ep2"
- address="/ep2"
- binding="wsHttpBinding"
- contract="MessagePatternDemo.IService1" />
- <endpoint name="mex"
- contract="IMetadataExchange"
- address="mex"
- binding="mexHttpBinding" />
- </service>
In the above configuration we are creating two EndPoints for the same service. The same service is exposed on different bindings. The client can access the same service, either on basicHttpBinding or wsHttpBinding. Both EndPoints are identified with different names like ep1 and ep2. In multiple EndPoints each EndPoint will be exposed on a different address with different names.
At the client side the same service can be consumed by passing an EndPoint name.
- Service1Client proxy1 = new Service1Client("ep1");
- var message = proxy1.message("dj");
- Console.WriteLine(message);
- Console.ReadKey(true);
We are passing ep1 as the name of the EndPoint, so the client will consume the service using basicHttpBinding. If you do not pass an EndPoint name at the time of proxy creation then the run time error will occur while calling the service.
In the above scenario, we exposed the same service on multiple bindings using two different EndPoints.
Multiple Address Scenario
There could be a scenario when you may want to expose the same service on multiple base addresses. You can have more than one base address in the service. The base address is created under the host as below:
You can add more than one base address using the add in baseAddresses section. The advantage of having a base address is that if we are moving the service from one server to another then only the base address needs to be changed and all EndPoints will work on the updated server. WCF allows us to provide multiple base addresses for each type of protocol. And at run time the corresponding endpoint will use the base address.
So you can expose IService1 on multiple EndPoints with more than one binding as below. We are exposing IService1 with basicHttpBinding and netTcpBinding both. At run time WCF will attach a corresponding base address to respective binding.
- <services>
- <service name="MessagePatternDemo.Service1">
- <endpoint name="ep1"
- address="/ep1"
- binding="basicHttpBinding"
- contract="MessagePatternDemo.IService1"/>
- <endpoint name="ep2"
- address="/ep2"
- binding="netTcpBinding"
- contract="MessagePatternDemo.IService1"/>
- <endpoint
- contract="IMetadataExchange"
- address="mex"
- binding="mexHttpBinding" />
- <endpoint address="mex1"
- binding="mexTcpBinding"
- contract="IMetadataExchange"/>
-
- <host>
- <baseAddresses>
- <add baseAddress="http://localhost:8081"/>
- <add baseAddress="net.tcp://localhost:8082"/>
- </baseAddresses>
- </host>
- </service>
-
- </services>
You may want to host the same service on different servers, in that scenario the service will also have the same contract and binding whereas a different address.
Multiple Contract Scenario
There could be a scenario when you will need to expose multiple Service Contracts. Service Contracts will be exposed on separate EndPoints.
Let us say we have two services IService1 and IService2 as below:
- [ServiceContract]
- public interface IService1
- {
- [OperationContract]
- string messagefromservice1(string name);
-
- }
-
- [ServiceContract]
- public interface IService2
- {
- [OperationContract]
- string messagefromservice2(string name);
-
- }
And the service is implemented as below:
- public class Service1 : IService1, IService2
- {
- public string messagefromservice2(string name)
- {
- return "Hello " + name + " from service1";
- }
-
- public string messagefromservice1(string name)
- {
- return "Hello " + name + " from service2";
- }
- }
In the config file we have created multiple EndPoints exposing IService1 and IService2 as below:
- <services>
- <service name="MessagePatternDemo.Service1">
-
- <endpoint name="ep1"
- address="/ep1"
- binding="basicHttpBinding"
- contract="MessagePatternDemo.IService1"/>
-
- <endpoint name="ep2"
- address="/ep2"
- binding="basicHttpBinding"
- contract="MessagePatternDemo.IService2"/>
-
- <endpoint
- contract="IMetadataExchange"
- address="mex"
- binding="mexHttpBinding" />
-
-
- <host>
- <baseAddresses>
- <add baseAddress="http://localhost:8081"/>
- </baseAddresses>
- </host>
- </service>
-
- </services>
At the client side while consuming a service you will get information that there are two service contracts as part of the service. As you see in the Add Service Reference dialog, there are two services listed and they are IService1 and IService2
To use these service you will need to create separate proxies. Both services can be consumed at the client as below:
- Service1Client proxy1 = new Service1Client();
- var message = proxy1.messagefromservice1("dj");
- Console.WriteLine(message);
-
- Service2Client proxy2 = new Service2Client();
- var message1 = proxy2.messagefromservice2("dj");
- Console.WriteLine(message1);
-
- Console.ReadKey(true);
On running you will get output as below:
Having multiple EndPoints for services are sometimes essential for a good service design. You may want to expose the same service on different EndPoints for Internet users whereas for an Intranet user on a separate EndPoint. I hope this article is useful for you.