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:
svcutil.exe
http://localhost:8000/?wsdl
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.
1 comment:
Nice stuff!!!
Post a Comment