Enabling NetTcpBinding for Performance gains and binary serialization

I have a web simple web service which as just basic http binding, below are the steps to steps to enable netTcpBinding

<services>
      <service name="TestWcfWebService.Service.PersonService">
        <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration="" 
          contract="TestWcfWebService.Contracts.IPerson" />
</service>

My webservice is at http://localhost/TestWcfWebService-Server/Service.svc?wsdl

Below you can see the methods when you add reference to this service using wcfTestclient

All the methods work fine.

Let us add another endpoint with netTcpBinding

 <services>
      <service name="TestWcfWebService.Service.PersonService">
        <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration="" 
          contract="TestWcfWebService.Contracts.IPerson" />
        <endpoint address="tc" binding="netTcpBinding" bindingConfiguration="" 
                  contract="TestWcfWebService.Contracts.IPerson" />
          </service>
    </services>

When you browse to the svc file you will get an error

Could not find a base address that matches scheme net.tcp for the endpoint with binding NetTcpBinding. Registered base address schemes are [http].

I am using Windows7 , IIS7, App pool 4.0 Integrated. What the error is telling is you have not enabled the net.tcp binding protocol on you website. Go to your application, right click, manage application, and advance setting

Add net.tcp to the Enabled Protocol

Now browse to the svc file.

Now let us try to add reference to this service using wcfTestClient

You can see now we have the net Tcp endpoint, http binding still works fine, when you try to invoke addPerson you get error

Could not connect to net.tcp://localhost/TestWcfWebService-Server/Service.svc/tc. The connection attempt lasted for a time span of 00:00:02.0112011. TCP error code 10061:

The reason for this error is because your Net.Tcp Listener Adapter Service is not started.

When you try to start Net.Tcp Listener Adapter Service you may get the below error

Windows could not start the Net.Tcp Listener Adapter service on Local Computer.
Error 1068: The dependency service or group failed to start.
This error is because Net TCP depends on Net.Tcp Port Sharing and Windows Process Activation Service, make sure these services are started as well.

After these services are started Net TCP Binding is all set.

Below is the code in VB when you need to invoke a specific end point after adding service reference, first look at the wsdl on the client after adding reference, you will find the endpoint name BasicHttpBinding_IPerson and NetTcpBinding_IPerson

My WSDL

<wsdl:service name="PersonService">
    <wsdl:port name="BasicHttpBinding_IPerson" binding="tns:BasicHttpBinding_IPerson">
      <soap:address location="http://localhost/TestWcfWebService-Server/Service.svc/basic" />
    </wsdl:port>
    <wsdl:port name="NetTcpBinding_IPerson" binding="tns:NetTcpBinding_IPerson">
      <soap12:address location="net.tcp://localhost/TestWcfWebService-Server/Service.svc/tc" />
      <wsa10:EndpointReference> 

Here I am invoking net tcp binding endpoint.

    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgsHandles MyBase.Load 
        client = New PersonClient("NetTcpBinding_IPerson") 
    End Sub 

Possible other errors you may encounter

I am using NetworkService as the Identity of the application pool running this WCF service application.

When I try to add reference I get the below error

The document was understood, but it could not be processed.

– The WSDL document contains links that could not be resolved.

– There was an error downloading ‘http://localhost/TestWcfWebService-Server/Service.svc?xsd=xsd0&#8217;.

– The underlying connection was closed: An unexpected error occurred on a receive.

– Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

– An existing connection was forcibly closed by the remote host

Metadata contains a reference that cannot be resolved: ‘http://localhost/TestWcfWebService-Server/Service.svc?wsdl&#8217;.

There was no endpoint listening at http://localhost/TestWcfWebService-Server/Service.svc?wsdl that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

The remote server returned an error: (404) Not Found.

If the service is defined in the current solution, try building the solution and adding the service reference again.

This error is because of the pool identity does not have the right privileges to C:\windows\Temp, when I ran the pool with identity as myself no problem,

WCF In Action

1.    Create a blank solution

image

2.    Add new class library project to the solution
image
3.    Rename Class1.vb as IPerson.vb, edit the file, and change class to an interface

Public Interface IPerson

End Interface

4.    To WcfIn3Tiers.Service.Contracts add reference to System.ServiceModel
image

5.    Change IPerson file to look like below

Imports System.ServiceModel
<ServiceContract()> _
Public Interface IPerson

End Interface

6.    Add new class library project WcfIn3Tiers.Entities to the solution
image

7.    Rename Class1 to Person.
8.    To WcfIn3Tiers.Entities add reference to System.Runtime.Serialization
9.    Edit person class to look like below

Imports System.Runtime.Serialization
<DataContract()> _
Public Class Person
<DataMember()> _
Public personId As String
<DataMember()> _
Public firstName As String
<DataMember()> _
Public lastName As String
End Class

10.    To WcfIn3Tiers.Service.Contracts add reference to WcfIn3Tiers.Entities project
image

11.    Edit IPerson, the code should like shown below

Imports System.ServiceModel
Imports WcfIn3Tiers.Entities
<ServiceContract()> _
Public Interface IPerson
<OperationContract()> _
Sub addPerson(ByVal personEntity As Person)
<OperationContract()> _
Function getPeople() As List(Of Person)
<OperationContract()> _
Sub removePerson(ByVal pId As String)
End Interface
12.    Add a new class library WcfIn3Tiers.Service
image

13.    To this project add reference to System.ServiceModel, WcfIn3Tiers.Entities, WcfIn3Tiers.Service.Contracts
14.    Rename Class1 to PersonService and edit it to look like below
Imports WcfIn3Tiers.Entities
Imports WcfIn3Tiers.Service.Contracts
Imports System.ServiceModel
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single)> _
Public Class PersonService
Implements IPerson

Private _listOfPeople As New List(Of Person)

Public Sub addPerson(ByVal personEntity As Entities.Person) Implements Contracts.IPerson.addPerson
personEntity.personId = Guid.NewGuid.ToString
_listOfPeople.Add(personEntity)
End Sub
Public Function getPeople() As System.Collections.Generic.List(Of Entities.Person) Implements Contracts.IPerson.getPeople
Return _listOfPeople
End Function

Public Sub removePerson(ByVal pId As String) Implements Contracts.IPerson.removePerson
_listOfPeople.Remove(_listOfPeople.Find(Function(e) e.personId.Equals(pId)))
End Sub
End Class
15.    Now we have defined the service contract, data contract and the service. Which in the remoting world we used to call Interface. Entities and Core.

Hosting this Service in a Console Application
16.    Add a console application to the solution call it WcfIn3Tiers.ConsoleHost
image

17.    To WcfIn3Tiers.ConsoleHost add reference to WcfIn3Tiers.Service project and System.ServiceModel
18.    Edit model1.vb file to look like below

Imports WcfIn3Tiers.Service
Imports System.ServiceModel
Module Module1

Sub Main()
Dim myWcfHost As ServiceHost = New ServiceHost(GetType(PersonService))
myWcfHost.Open()
Console.WriteLine(“Service is up and running…………”)
Console.ReadLine()
myWcfHost.Close()
End Sub

End Module

19.    Build the solution
20.    Configure the end points
21.    Add new item in general section pick app.config

22.    App.config file contains some extras which we will not need just delete the <system.diagnostics> tag
23.    Right click app.config file and select open with .. if you have not already associated SvcConfigEditor.exe to open with, click add
image

24.    Click browse
25.    Browse to C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\ SvcConfigEditor.exe
26.    In Win7 I found it here “C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\SvcConfigEditor.exe”
27.    Friendly Name: WCF Configuration Editor

image

image

28.    Click OK
image
29.    Click Create a New Service
image
30.    Browse to bin\debug folder in the console application and select WcfIn3Tiers.service.dll.

image
31.    Then Select WcfIn3Tiers.Service.PersonService click open
image

32.    Click Next
image
33.    Click Next
image
34.    Click Next
image
35.    Next
image

36.    In the address type basic this a relative address. We will add the base address later
37.    Click on the Host and in the base Address section click new
image
38.    Click on
39.    Open the Endpoints, we have the basicHttpBinding we configured earlier. Let us now configure the metadata endpoint
40.    Open Advanced—> Service Behaviors
image
41.    Click New Service Behavior Configuration
image
42.    Click Add
image
43.    Select serviceMetadata
44.    Now select the actual service right on the top and configure the behavior
image
45.    Click  in the behaviorConfiguration dropdown and select NewBehavior
46.    Configure the metadata endpoint
47.    Right click Endpoints and select New Service Endpoints
image

48.    For the Contract click on the browse .. button
image

49.    Click GAC and select System.ServiceModel click open
image

50.    Select IMetadataExchange
51.    Close the editor save the changes
52.    The app.config will look like below
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>

<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name=”NewBehavior”>
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration=”NewBehavior” name=”WcfIn3Tiers.Service.PersonService”>
<endpoint address=”basic” binding=”basicHttpBinding” bindingConfiguration=””
contract=”WcfIn3Tiers.Service.Contracts.IPerson” />
<endpoint address=”mex” binding=”mexHttpBinding” bindingConfiguration=””
contract=”IMetadataExchange” />
<host>
<baseAddresses>
<add baseAddress=”http://localhost:8899/WcfIn3Tiers” />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

53.    Set WcfIn3Tiers.ConsoleHost as startup project and run the solution
image

54.    To test service
55.    Open VS command prompt, type in
wcftestclient http://localhost:8899/WcfIn3Tiers
56.    The test client opens up and display service for testing
image
57.    Double click on addPerson, punch in the firstName and lastName and click Invoke
image
58.    You will get a null response
59.    To test getPeople double click it and hot invoke
image
60.    You should see person you just added
61.    To test removePerson copy the PersonId from getPerson and punch it into the value column and hit invoke
image
62.    This concludes testing the service

Hosting the service in IIS
63.    We will create a new folder in C:\Temp\WcfIn3Tiers call it web
image
64.    Create new Virtual directory call it WcfIn3TierSite and map it C:\Temp\WcfIn3Tiers\Web
image

image
65.    Finish
66.    Add a new website project to the solution, select WCF Service
image

67.    Location HTTP and point to the newly created VD
68.    When the new project is created, under the app_code you will have 2 file IService.vb and Service.Vb, we will not need them just delete.
69.    Add reference to WcfIn3Tier.Service project
70.    The important file we will be working on is Service.svc file, double click it. The file will have code as shown below
<%@ ServiceHost Language=”VB” Debug=”true” Service=”Service” CodeBehind=”~/App_Code/Service.vb” %>
71.    Modify it to look like below
<%@ ServiceHost Language=”VB” Debug=”true” Service=”WcfIn3Tiers.Service.PersonService” %>
72.    Open the web.config with WCF Configuration Editor as we did earlier
image

73.    Click on the service and change the service name by click on the browse button
image

74.    In the bin directory select WcfIn3Tiers.Service.dll, then select the PersonService
image
75.    Click open
76.    Don’t worry about the Host. We will configure the end point. This project template already come configured with 2 endpoints we will just reuse them, but point to our person service contract
77.    Click on the 1st end point, in the address textbox add ws as the relative address. Then click on the contract textbox’s browse button
image
78.    Change the contact to IPerson by browsing to WcfIn3Tiers.Service.Contracts.dll
image
79.    Click Open, select WcfIn3Tiers.service.Contracts.IPerson
image
80.    We will leave mex endpoint as it is
81.    Save the file and exit
82.    To Test this, point the browser url to http://localhost/WcfIn3TierSite/Service.svc
image
83.    This is give WSDL url and how you can consume the service
84.    Open the WCFTestClient and point to the wsdl
image

85.    You will again see the familiar test client interface, go ahead and test the service as mentioned earlier

Creating a client to consume the service
86.    Add a new window forms application project to the solution
image

87.    Add Service reference
88.    Point to wsdl file for the service we just hosted in iis, click go, put MyPersonWebService in the Namespace textbox
image
89.    Vs will create all the proxy classes need
90.    Create a couple of textboxs and button as shown
image
91.    In the code behind

Imports WcfIn3Tiers.Client.MyPersonWebService
Public Class Form1
Private client As PersonClient
Private Sub AddButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddButton.Click
Dim p As New Person
p.FirstName = FnTextBox.Text
p.LastName = LnTextBox.Text
client.addPerson(p)
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
client.Close()
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
client = New PersonClient()
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ps As Person()
ps = client.getPeople()
DataGridView1.DataSource = ps
End Sub
End Class

92.    Set your client project as startup and test it out