Monday, June 18, 2012

First WCF Program for First Time WCF Programmers

Part 2


Now we will extend the WCF application developed in Part 1. In this part, we will use configuration file for the settings.



In the host project, add ApplicationConfiguration file “App.config”. Open the file and the file still do not have any settings configured.



<?xml version="1.0" encoding="utf-8" ?>

<configuration>

</configuration>

Now add a section for servicemodel as shown below:



<?xml version="1.0" encoding="utf-8" ?>

<configuration>

      <system.serviceModel>

            <services>

                 

            </services>

      </system.serviceModel>

</configuration>

Now we need to add services section. In the services section we can configure multiple services. For our application, we will add one service. We need to give the name of the service and as discussed each service is exposed using endpoints. So, add a section for endpoint and give values for Address, Contract and Binding. We can give relative path or the absolute path for the address. For the convenience to deploy the application in different environments we give relative path in the address

.

Absolute path in this application is http://localhost:8000/HelloWorld.



Now the hosted service should be able to expose itself to the outside the world by providing the implementation details to the client. For it to happen now we need to add another endpoint specifying the mexHttpBinding and IMetadataExchange. This basically provides the metadata of the service to the clients consuming the service. We do not need to provide wsdl file to the client. When client references to the service, he can get the wsdl file automatically generated if it is through Visual studio or the client can generate WSDL using utility SVSUtil.exe.



In our example, we follow the happy path. Let the Visual studio generate the stuff needed for consuming the service.



Now we will add the host base address. Since in the services configuration sections we have given relative paths, we need to configure the base address. This provides the developers the flexibility to change only the base address in any environment by making the service address as relative.

Also we need to add a behavior of the service to enable itself to be exposed through http request. Any client who requests the service using http will get the meta data of the service.



<?xml version="1.0" encoding="utf-8" ?>

<configuration>

      <system.serviceModel>

            <services>

                  <service name="HelloWorldService.HelloWorld">

                        <endpoint contract="HelloWorldService.IHelloWorld" address="HelloWorld" binding="basicHttpBinding"></endpoint>

                        <endpoint contract="IMetadataExchange" address="Mex" binding="mexHttpBinding"></endpoint>

                        <host>

                              <baseAddresses>

                                    <add baseAddress="http://localhost:8000"/>

                              </baseAddresses>

                        </host>

                  </service>

            </services>

            <behaviors>

                  <serviceBehaviors>

                        <behavior name="MyServiceBehavior">

                              <serviceMetadata httpGetEnabled="true"/>

                        </behavior>

                  </serviceBehaviors>

            </behaviors>

      </system.serviceModel>

</configuration>

Now try to test the host application by running a new instance and you will get the following error. This is because we did not add the service behavior to the service. So, configure the service behavior with the one we have defined in the above.

The contract name 'IMetadataExchange' could not be found in the list of contracts implemented by the service HelloWorld.  Add a ServiceMetadataBehavior to the configuration file or to the ServiceHost directly to enable support for this contract.



<?xml version="1.0" encoding="utf-8" ?>

<configuration>

      <system.serviceModel>

            <services>

                  <service name="HelloWorldService.HelloWorld" behaviorConfiguration="MyServiceBehavior">

                        <endpoint contract="HelloWorldService.IHelloWorld" address="HelloWorld" binding="basicHttpBinding"></endpoint>

                        <endpoint contract="IMetadataExchange" address="Mex" binding="mexHttpBinding"></endpoint>

                        <host>

                              <baseAddresses>

                                    <add baseAddress="http://localhost:8000"/>

                              </baseAddresses>

                        </host>

                  </service>

            </services>

            <behaviors>

                  <serviceBehaviors>

                        <behavior name="MyServiceBehavior">

                              <serviceMetadata httpGetEnabled="true"/>

                        </behavior>

                  </serviceBehaviors>

            </behaviors>

      </system.serviceModel>

</configuration>

Now try to test the application again. You will not see any error. Since, we access the service using http try browsing it using http://localhost:8000 and you will see the following in the IE.

HelloWorld Service



You have created a service.

To test this service, you will need to create a client and use it to call the service. You can do this using the svcutil.exe tool from the command line with the following syntax:




This will generate a configuration file and a code file that contains the client class. Add the two files to your client application and use the generated client class to call the Service. For example:

C#

class Test
{
    static void Main()
    {
        HelloWorldClient client = new HelloWorldClient();

        // Use the 'client' variable to call operations on the service.

        // Always close the client.
        client.Close();
    }
}



Visual Basic

Class Test
    Shared Sub Main()
        Dim client As HelloWorldClient = New HelloWorldClient()
        ' Use the 'client' variable to call operations on the service.

        ' Always close the client.
        client.Close()
    End Sub
End Class



Keep the service running and add a service reference to the client project as below:



 

Now if you go to the client configuration file, you will see two end points. One is http that we added declaratively in the configuration file and the other one that we did programmatically in the Part 1.

<client>

            <endpoint address="http://localhost:8000/HelloWorld" binding="basicHttpBinding"

                bindingConfiguration="BasicHttpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"

                name="BasicHttpBinding_IHelloWorld" />

            <endpoint address="net.tcp://localhost:9000/HelloWorld" binding="netTcpBinding"

                bindingConfiguration="NetTcpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"

                name="NetTcpBinding_IHelloWorld">

                <identity>

                    <userPrincipalName value="MyPC\ComputerName" />

                </identity>

            </endpoint>

        </client>



Now remove the interface that we have added in the Part 1 in the client program file. Since the client is having reference to the WSDL generated. Observe the class and other files generated by the VS after referencing the service for more understanding. Visual studion also generated a client proxy to be used in our coding MyServiceReference.HelloWorldClient.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;



namespace Client

{

   

    class Program

    {

        static void Main(string[] args)

        {

            //IHelloWorld proxy = ChannelFactory<IHelloWorld>.CreateChannel(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:9000/HelloWorld"));

           

            MyServiceReference.HelloWorldClient proxy = new Client.MyServiceReference.HelloWorldClient();

            Console.WriteLine(proxy.ShowData("Hello World From Client"));

            Console.ReadLine();



        }

    }

}

Now run the client program and you will get the following error (Make sure that the host application is running before this one):

An endpoint configuration section for contract 'MyServiceReference.IHelloWorld' could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.

This is due to the app.config in the client project has two endpoints defined and so the application does not know which one to use to communicate with the service. So, comment the one endpoint which is referring to NetTcpBinding and run the program again.



<client>

            <endpoint address="http://localhost:8000/HelloWorld" binding="basicHttpBinding"

                bindingConfiguration="BasicHttpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"

                name="BasicHttpBinding_IHelloWorld" />

            <!--<endpoint address="net.tcp://localhost:9000/HelloWorld" binding="netTcpBinding"

                bindingConfiguration="NetTcpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"

                name="NetTcpBinding_IHelloWorld">

                <identity>

                    <userPrincipalName value="MyPC\ComputerName" />

                </identity>

            </endpoint>-->

        </client>




If you want to test both the end points we need to specify the endpoint configuration name explicitly. To test this, uncomment the endpoint configuration that we did in the previous step and modify the program code as below:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;



namespace Client

{

    class Program

    {

        static void Main(string[] args)

        {

            //IHelloWorld proxy = ChannelFactory<IHelloWorld>.CreateChannel(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:9000/HelloWorld"));

           

            MyServiceReference.HelloWorldClient proxy = new Client.MyServiceReference.HelloWorldClient("BasicHttpBinding_IHelloWorld");

            Console.WriteLine(proxy.ShowData("Hello World From Client using basicHttpBinding"));



            proxy = new Client.MyServiceReference.HelloWorldClient("NetTcpBinding_IHelloWorld");

            Console.WriteLine(proxy.ShowData("Hello World From Client using netTcpBinding"));

           

            Console.ReadLine();



        }

    }

}

You will see that the service responded using http and also the net Tcp as below:


This completes our simple coding for WCF and all the credit for simplicity to goes to Microsoft for making our developers life so simple and easy.

Happy coding!!!

Part 1

1 comment:

Post a Comment