Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#5.0

Default Endpoints and Default Protocol Mapping in WCF 4.0/4.5

4.91/5 (20 votes)
14 Apr 2014CPOL10 min read 57.5K   403  
This article describes default endpoints and protocol mapping behaviors in WCF 4.0/4.5

Table of Contents

Introduction

WCF 4.0 shipped with lots of new features which made developer's life much easier. one of them is Simplified Configuration. WCF 4.0 simplified configuration section by providing the support of default endpoints, default protocol mapping, default binding and behavior configurations. These new features made it possible to host configuration-free services. This was the most significant improvement for the developer's experience prospective. I'll explain default endpoint and default protocol mapping concepts step by step in this article.

Default Endpoints

In WCF 3.x, if any one try to host a service without configuring any endpoints, the ServiceHost instance throws an System.InvalidOperationException informing that there should be at least one endpoint configured.

Image 1

But with the WCF 4.0, the runtime automatically adds one or more “default endpoints”, thereby making the service usable without any configuration. Actually when the service host application invokes Open on the ServiceHost instance, it builds the internal service description from the configuration file and service assembly respectively along with any explicit configuration the host application has and if the number of configured endpoints is found zero, it calls AddDefaultEndpoints method (a new public method of the ServiceHost class) to add one or more endpoints to the service description based on the service’s base addresses configuration. In case of IIS scenarios, it would be the .svc address. The rule can be stated as below-

The AddDefaultEndpoints method adds one default endpoint per base address for each service contract implemented by the service.

If the service implements one service contract (say IA) and the host is configured with two base addresses (say one for TCP and another for HTTP), then the AddDefaultEndpoints method will add two default endpoints to the service (one per base address with the service contract. combination would be TCP with IA and HTTP with IA).

If the service implements two service contracts (say IA and IB) and the host is configured with a single base address (say for TCP in this case), then the AddDefaultEndpoints method will add two default endpoints to the service (one per base address with each service contract. combination would be TCP with IA and TCP with IB).

If the service implements two service contracts (say IA and IB) and the host is configured with two base addresses (say one for TCP and another for HTTP), then the AddDefaultEndpoints method will add four default endpoints to the service (one per base address with each service contract. combination would be TCP with IA, TCP with IB, HTTP with IA and HTTP with IB).

So in general for a service with zero endpoint configurations, if the total no of configured base address are n and the total no of implemented service contract are m, then the AddDefaultEndpoints method will add n x m default endpoints to the service.

Let’s try to grasp this concept through an example. For the demo I've created a simple service to demonstrate the default endpoints creation. I've defined IHusband, IWife & IKids service contracts and after that I've created a service FamilyService by implementing these service contracts as per below-

C#
[ServiceContract]
public interface IHusband
{
   [OperationContract]
   void WelcomeHusband(string name);
}

[ServiceContract]
public interface IWife
{
   [OperationContract]
   void WelcomeWife(string name);
}

[ServiceContract]
public interface IKids
{
   [OperationContract]
   void WelcomeKids();
}

public class FamilyService : IHusband, IWife, IKids
{
   public void WelcomeHusband(string name)
   {
      Console.WriteLine("Hello Mr. {0}", name);
   }

   public void WelcomeWife(string name)
   {
      Console.WriteLine("Hello Mrs. {0}", name);
   }

   public void WelcomeKids()
   {
      Console.WriteLine("Hi Kids!");
   }
}

Then I've created a console application to host the service using ServiceHost class and added a base address for HTTP programmatically to it without any configuration file associated with the host application. See the code below-

C#
var host = new ServiceHost(typeof(FamilyService), new Uri("http://localhost:8080/familyservice"));

try
{
   host.Open();
   PrintServiceInfo(host);
   Console.ReadLine();
   host.Close();
}
catch (Exception ex)
{
   Console.WriteLine(ex.Message);
   host.Abort();
}

Now run the host and you will find there are three endpoints in the console window added to the service by default, one for each service contract for the HTTP base address.

Image 2

Now add one more base address for TCP programmatically to it like-

C#
var host = new ServiceHost(typeof(FamilyService),
               new Uri("http://localhost:8080/familyservice"),
               new Uri("net.tcp://localhost:8085/familyservice"));

and run the host application again. Now you will see there are six endpoints in the host console window, three for the TCP base address one per service contract and three for the HTTP base address one per service contract.

Image 3

So you have seen in both cases how ServiceHost instance adds default endpoints to the service behind the scene for the provided base address(s). Actually ServiceHost instance invokes the AddDefaultEndpoints method implicitly to add default endpoints. So with WCF 4, you can use ServiceHost class to host any service without any application configuration file.

Now it is important to note that at this point if any service has been configured with a single endpoint, then this default endpoints behavior will no longer work. To check this, just add one endpoint to the FamilyService service like

C#
host.AddServiceEndpoint(typeof(IHusband),new  NetTcpBinding(), "pipe");

and run the host application, you'll observe that there is only single endpoint displaying in the host console window. No default endpoints.

Image 4

But if you still like to have default endpoints to the service along with your own, just invoke the AddDefaultEndpoints method explicitly like-

C#
host.AddServiceEndpoint(typeof(IHusband),new  NetTcpBinding(), "pipe");
host.AddDefaultEndpoints();

and run the host application again, you'll now find all possible default endpoints are displaying on the console host windows along with your own endpoint.

Image 5

The default endpoint behavior will also work if you configure the base address(es) through the configuration file. However in this case you'll need to configure the service with desire base address(es) through the configuration file. To see this, just create a ServiceHost instance like-

C#
var host = new ServiceHost(typeof(FamilyService));

and add configuration file (in this case app.config file) to the console host application and configure the service with a single base address like-

ASP.NET
<system.serviceModel>
   <services>
     <service name="FamilyServiceLibrary.FamilyService">
     <host>
           <baseAddresses>
              <add baseAddress="net.pipe://localhost/familyservice" />
           </baseAddresses>
      </host>
     </service>
   </services>
</system.serviceModel>

and run the console host application, you'll see all default endpoints on the console window.

Image 6

Default Endpoints Behavior in IIS/WAS Hosting

Default endpoint behavior can also be observed in case of service is hosted in IIS. With WCF 4.0, if a service is going to be hosted in IIS with default configuration, then the WCF activation logic will create the ServiceHost instance behind the scene and configure the service with default HTTP endpoint(s). If a service implements only one service contract, then a single default HTTP endpoint would be added, and if a service implements more than one service contract the resulting ServiceHost instance will be configured with one HTTP endpoint per contract.

Let’s host our FamilyService in IIS to understand this concept. For the demo, I've created a WCF Service Web Site and added the reference of our FamilyService project (FamilyServiceLibrary) to it and renamed the service.svc file to Family.svc (not necessary). Then opened the FamilyService.svc and updated the ServiceHost directive as below-

ASP.NET
<%@ ServiceHost Service="FamilyServiceLibrary.FamilyService" %>

As we know, when a service is hosted in IIS/WAS, then the base address is determined by the IIS virtual directory hosting the service along with the name of the .svc file, so there is no need to worry about the base address(es) configuration. Now I've just ensured that whether service metadata is enabled or not through the web.config file like-

ASP.NET
<serviceMetadata httpGetEnabled="true" />

Finally I've hosted our FamilyService in the IIS. Now when the first time any one browse to Family.svc, the WCF activation logic will create the ServiceHost instance and it will add three default HTTP endpoints for the FamilyService type (one for each service contract). You can verify these default endpoints by browsing to the WSDL definition and you’ll find three <port> elements within the <service> element.

Image 7

Let’s realise this behavior for other protocols too in case of IIS (version > 7.0)/Windows Process Activation Services (WAS) hosting. As we know WAS allows WCF service activation over any transport (TCP/MSMQ/NamedPipe etc) in IIS (version > 7.0). So I've enabled TCP and NamedPipe protocols to our FamilyService through Interned Information Seerver (IIS) Manager as below-

Image 8

Now you can verify default endpoints by browsing to the WSDL definition for TCP and NamePipe protocols too. Just see the nine <port> elements within the <service> element. Here when the first time Family.svc browsed, the WCF activation logic has created the ServiceHost instance and it added nine default endpoints (three for HTTP, three for TCP and three for NamedPipe for each service contract) for the FamilyService type.

Image 9

If you don't want default endpoints behavior in your service, and to want to configure your own endpoint(s), just configure your service with a relative address in web.config file

ASP.NET
<services>
     <service name="FamilyServiceLibrary.FamilyService">
       <endpoint address="ws" binding="wsHttpBinding" bindingConfiguration=""
         contract="FamilyServiceLibrary.IHusband" />
     </service>
</services>

and browse the Family.svc; you'll find there is only one <port> element within the <service> element in the WSDL definition.

Image 10

Now what if you still want default endpoints behavior to the service along with your own endpoint(s)? Well this is bit tricky in this case. You'll need to use ServiceHostFactory class. You can intercept ServiceHost creation using a ServiceHostFactory. So in order to achieve this, first I've created a FamilyServiceHost class by deriving from the ServiceHost class and overridden its OnOpening method to configure the service with a desire endpoint (relative) along with default endpoints as below-

C#
public class FamilyServiceHost : ServiceHost
{
    public FamilyServiceHost(Type serviceType, params Uri[] baseAddresses) :
                                                  base(serviceType, baseAddresses) { }

    protected override void OnOpening()
    {
        base.OnOpening();

        this.AddServiceEndpoint(typeof(IHusband),
            new WSHttpBinding(), "ws");

        this.AddDefaultEndpoints();
    }
}

Then I've created FamilyServiceHostFactory class by deriving from the ServiceHostFactory class and overridden its CreateServiceHost method in order to create instance of our custom service host class- FamilyServiceHost as below-

C#
public class FamilyServiceHostFactory : ServiceHostFactory
{
    protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType,
                                                                    Uri[] baseAddresses)
    {
        return new FamilyServiceHost(serviceType, baseAddresses);
    }
}

And finally I've specified our custom host factory class in Family.svc file using the Factory attribute as below-

ASP.NET
<%@ ServiceHost Service="FamilyServiceLibrary.FamilyService"
                    Factory="FamilyServiceLibrary.FamilyServiceHostFactory" %>

Now when you browse Family.svc first time, the WCF activation logic will create the custom ServiceHost instance and it will add your own endpoint along with default HTTP endpoints for the FamilyService type (one for each service contract). You can verify these default endpoints and your own endpoint by browsing to the WSDL definition and you’ll see there are four <port> elements within the <service> element.

Image 11

WCF 4.5 shipped with a nice feature of HTTPS default endpoints. So if your IIS is SSL configured, and you are going to host a WCF 4.5 service in IIS with default configuration, then the WCF 4.5 activation logic will create the ServiceHost instance behind the scene and configure the service for both default HTTP and HTTPS endpoint(s).

So if our FamilyService is going to be hosted in SSL configured IIS, we'll get six default endpoints- three for HTTP and three for HTTPS. See the screen shot below-

Image 12

If you have SSL configured IIS, but don't want to use HTTPS default endpoint(s), you can get rid of it by using the HTTPS scheme mapping from the configuration file as shown below-

ASP.NET
<system.serviceModel>
    <protocolMapping>
        <remove scheme="https"/>
    </protocolMapping> 
</system.serviceModel>

Default Protocol Mapping

Have you noticed in above examples how WCF chosen to use the BasicHttpBinding for the default HTTP endpoints, the NetTcpBinding for the default TCP endpoints and the NetNamedPipeBinding for the default NamedPipe endpoints? How did WCF decide which binding to use for a particular based address? The answer to this question is quiet simple. WCF defines a default protocol mapping between transport protocol schemes (e.g., http, net.tcp, net.pipe, etc) and the built-in WCF bindings. The default protocol mapping is defined in the .NET 4 machine.config.comments file and it looks like as below-

ASP.NET
<system.serviceModel>
   <protocolMapping>
      <add scheme="http" binding="basicHttpBinding" bindingConfiguration="" />
      <add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration=""/>
      <add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration=""/>
      <add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration=""/>
   </protocolMapping>
...
</system.serviceModel>

One can override these mappings at the machine level by modifying the mapping for each protocol scheme. Or you can also override mapping(s) within the scope of an application by overriding this section within your application/web configuration file.

Let’s realise this behavior. I've overridden the default binding mapping for the HTTP protocol scheme from BasicHttpBinding to WSHttpBinding in the app.config for our console service host application like below-

ASP.NET
<protocolMapping>
   <add scheme="http" binding="wsHttpBinding" bindingConfiguration="" />
</protocolMapping>

and run the host application. You can now observe that there are three default endpoints (one for each contract) displaying on the console window using WSHttpBinding in stead of BasicHttpBinding for the HTTP protocol scheme.

Image 13

Similarly you can realise this behavior for our IIS hosted service too by overriding the default binding mapping for the HTTP protocol scheme from BasicHttpBinding to WSHttpBinding in the web.config. You can verify that HTTP default endpoints now using WSHttpBinding in stead of BasicHttpBinding by browsing to the WSDL definition for <port> elements within the <service> element.

Image 14

Once WCF determines which binding to use with the help of the protocol mapping table, it uses the default binding configuration when configuring the default endpoint.

If you want to override the default binding mapping for the protocol scheme, you can override the same for a particular binding via configuration file.

Conclusion

So I've explored default endpoints behavior and default protocol mapping behavior in this article. I'll explore some more features in the coming articles. Hope you've now good understanding about these concepts. Happy coding!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)