Writing your first WCF client

Posted on 7/23/2008 @ 6:45 AM in #WCF by | Feedback | 25047 views

This is in continuation to writing your first WCF service.

Now, that you've packaged that very valuable "Hello World" functionality, you need to next write some code to check and see if you can indeed use such a service. There could be 2 situations here

a) You have pre-distributed the metadata as a definition of the interface, or a dll that contains the IHelloWorld interface., OR

b) You expect clients to generate proxies on the fly, by using the metadata that you expose using the mex end point.

 

Y'know, option #b is  simpler, so I'm gonna talk about that first.

  1. Go ahead and create a new console app.
  2. Add a new service reference to http://localhost:8731/Design_Time_Addresses/MyServices/HelloWorld/mex .. which incidently was the same endpoint address that you were exposing the metadata endpoint at. Call this new reference, the "HelloWorldReference".
  3. Go write some code, like this -
  4.    1: static void Main(string[] args)
       2: {
       3:     HelloWorldReference.HelloWorldClient client = 
       4:         new HelloWorldClient.HelloWorldClient();
       5:     Console.WriteLine(client.SayHello("Sahil"));
       6:     client.Close();
       7:     Console.Read();
       8: }
  5. Now, make sure that your service that you wrote per this article is running ..
  6. Hit F5 to run the client, here are the results -

Note: There is a bug in the generated code in the Reference.cs . Apparently, they didn't use best practices while generating the Reference.cs, and if your consoleapp name happens to be the same as ServiceName+"Client", then you get a compilation error - because of a name clash between the proxy name, and generated class name. Simply use the "global::" keyword to get rid of that error.

The error text is -

The type name 'HelloWorldReference' does not exist in the type 'HelloWorldClient.HelloWorldReference.HelloWorldClient'

Now, lets look at option #a - where you don't want to expose metadata, but instead, you have pre-distributed the contract to your clients as a DLL.

Well, in such a scenario, use the following steps -

  1. Add a reference to the contract dll.
  2. Write code as below:
  3.    1: static void Main(string[] args)
       2: {
       3:     IHelloWorld helloWorld = 
       4:         ChannelFactory<IHelloWorld>.CreateChannel(
       5:         new WSHttpBinding(), new 
       6:             EndpointAddress(
       7:             "http://localhost:8731/Design_Time_Addresses/MyServices/HelloWorld/"
       8:             ));
       9:     Console.WriteLine(helloWorld.SayHello("Sahil"));
      10: }

    What that code does, is that it first creates an instance of the client channel using the CreateChannel method, and then it can use that channel to merrily call whatever methods it wishes to - as defined by the interface.
     
    Run the app, you should see the same results as before.

Now, the above code .. especially the first line, is an eye sore. More than an eyesore, you are embedding hardcoded locations for end points inside your code. Not just locations, but the binding information, basically the entire endpoint information is hardcoded in code. Not good!

Luckily, you have just as much flexibility at the client, as you do at the server. Use the following steps:

  1. Create a definition of the endpoint in the app.config for the client -
  2.    1: <?xml version="1.0" encoding="utf-8" ?>
       2: <configuration>
       3:     <system.serviceModel>
       4:         <bindings />
       5:         <client>
       6:             <endpoint address="http://localhost:8731/Design_Time_Addresses/MyServices/HelloWorld/"
       7:                 binding="wsHttpBinding" bindingConfiguration="" contract="MyServices.IHelloWorld"
       8:                 name="HelloWorldSvc" />
       9:         </client>
      10:     </system.serviceModel>
      11: </configuration>

  3. Create the channel, using a proxy .. as shown in the code below:

  4.    1: static void Main(string[] args)
       2: {
       3:     ChannelFactory<IHelloWorld> helloWorldProxy = 
       4:         new ChannelFactory<IHelloWorld>("HelloWorldSvc");
       5:     helloWorldProxy.Open();
       6:     IHelloWorld helloWorld = helloWorldProxy.CreateChannel();
       7:     Console.WriteLine(helloWorld.SayHello("Sahil"));
       8:     helloWorldProxy.Close();
       9: }

  5. Run the above app, you should see the same results.

Now, I'd argue that Option #a here is a better choice. Why? because in option #a, you would have added a reference to only the interface IHelloWorld, the implementation is powered by the service host. AND, you didn't hard-tie your client to the service reference, i.e. generated proxy. In other words, the above code, will work, EVEN IF, the "mex" endpoint was missing.

_________________________________

Okay, so next we talk about hosting this service in IIS7. w00t!

Sound off but keep it civil:

Older comments..


On 7/23/2008 2:00:40 AM Gabriel said ..
Sahil, great article, this one and the other two about WCF services too, thanks!

There is a typo on line 4 of option b code:

HelloWorldReference.HelloWorldClient client =


new HelloWorldClient.HelloWorldReference.HelloWorldClient();

I think the first HelloWorldClient after new should not be there.

Thanks again,

Gabriel


On 7/23/2008 6:45:47 AM Sahil Malik said ..
Thanks Gabriel. It's fixed now. :)


On 8/6/2008 2:39:37 AM Sherly said ..
Great Sahil....Am a beginner and ur articles is really useful and to the point...Thanks


On 9/2/2008 7:03:02 AM SP.Murugesan said ..
How to host the service on IIS server running on Windows 2008 Server ? I need to allow more than 5 WebClient to consume simultaneously.I Succeeded on running Client & Service on the localhost.Same(uhh..) can't running on the Remote Server.any suggestion Sahil ?


On 11/16/2008 5:57:39 PM Shyam Gudi said ..
Great useful article for WCF beginners


On 11/17/2008 1:38:33 PM Dave said ..
OK, this I know, but how would you configure a client to connect to a WCF IIS Hosted service that is not on the same machine i.e. in a distributed environment? Localhost is localhost, my client is not on localhost. Please advise... Thank you


On 4/9/2009 11:19:20 AM Sahil Malik said ..
Dave - just change the web.config to point to wherever your svc is!


On 4/22/2009 4:03:04 PM Dave said ..
Lines 3 and 4 of the first code block should read


HelloWorldReference.HelloWorldClient client = new HelloWorldReference.HelloWorldClient();


as pointed out by Gabriel


On 7/1/2009 1:53:51 PM Mona said ..
Great job, very helpful. Clear and neat explanation. Thanks a ton!


On 8/18/2009 7:15:15 PM M Ramesh said ..
This is amazing material for a beginner !!!


On 9/9/2009 8:18:33 AM Vijay said ..
hey sahil


Its a great article to start with.


I have a doubt with respect to option a i.e predistributed the contract in a dll to client.In this case how will the client will be aware of the address and binding information to be used at client ?


On 11/19/2009 2:04:06 AM Dharmesh said ..
Hi sahil,


Nice and very helpful article for WCF beginner


On 11/30/2009 6:54:05 AM Razi said ..
Thanks buddy for explaining it in a really simple way.You article Rocks.


On 6/2/2010 10:55:04 AM Elissa said ..
Thank you very much.. very helpful


On 6/4/2010 1:05:14 PM Clem said ..
When adding the service referece with the mex URL, it throws a "There was an error downloading metadata from the address. Please verify that you have entered a valid address.


On 6/4/2010 1:12:30 PM Clem said ..
Another point. I like your tutorials, in particular the step by step instructions are very clear. Typically, a web service would not be consumed by a console application. It would be extremenly helpful if you could add some detail on how to set up the webservice in IIS and then create a client application to consume the service. This is the most complicated part. Adding the folder as an IIS virtual does not work. There is obviously much more required to actually publish/host a service in IIS. (Maybe that's why you didn't get into that. It's the most complicated and involved process). The example assumes the console app is in the same solution as the service. This will rarely be the case. The service needs to be external and consumed separately.


Also, it would be helpful to describe how to correct the invalid address (design_time_addresses). Most companies will require a specific address. Retyping the address to put in what you want is not likely to work of course. There will be much more to this as well.


Thanks again.


On 6/4/2010 2:06:14 PM Sahil Malik said ..
Clem,

I do have another article on this very topic. Please click on the wcf category on the left, you'll find it.

Sahil


On 6/16/2010 10:15:06 AM C-Sheep said ..
Great tutorials, thanks a lot!


But this client development is too hard to understand, two of your three exmaple do not work. The URLs are all wrong. The only working example is the one with the Service Reference, and even here I had to assign the URL of my own webservice "http://localhost:8000/HelloWorld.svc" and not "http://localhost:8731/Design_Time_Addresses/MyServices/HelloWorld/mex". What is mex? And where is it? There are now again an endless number of questions, issues, trouble. This is totally complicated, and I worked with lots of examples I found in the WWW. I am a beginner, and I don't know what to do when an error occurs. I just do not understand this stuff. Beginner tutorials which do not work when I exactly repeat everything 1:1 of your or other peoples examples are completely frustrating.


On 7/23/2010 1:20:34 PM andrew said ..
If you want an example of what mex is watch this video. It is an hour long and mex is explained towards the end.

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032344312&Culture=en-US

You will have to sign in with a valid Windows Live Id ... you can then download the video and watch it in windows media player.


On 12/6/2010 9:31:40 AM jamal said ..
Hi

I need to consume WCF Services without those ways that you have mentioned.


I want to develope a programme in which the users can type a url and the method-name and define its input and output parameter datatypes.


any idea whoud be appreciated.


I wish I asked clearly.


sorry, english is not my first language.


Thanks in advance.


On 1/29/2011 5:56:46 AM naveen said ..
Thanks for the artical , Help me alot


Expecting few more articals on wcf.

Thanks again


On 7/26/2011 8:51:05 AM Koushal said ..
Hi Sahil,

Great article..


I faced a problem though when I run the client.


The service call fails with an exception "The caller was not authenticated by the service".


I tried using basicHttpBinding instead of wsHttpBinding and it works.


But I wish to know why something that is working for the rest of the world isn't working for me.


Haven't seen anyone complaining about the same thing in any of the above posts.

I've ensured that I'm doing things in the exact way as you've mentioned in your article.


My service is hosted in IIS 7 on Windows Server 2008 R2 x64


On 11/10/2011 1:51:50 AM ad said ..
Nice stuff Sahil,


Where can I find your article on IIS, Console hosting.


On 2/20/2012 4:12:15 AM srilatha vuyyuru said ..
Got this error when trying to execute. could i please get a solution for this:

Could not connect to http://localhost:8731/Design_Time_Addresses/MYwcf/HelloWorld/. TCP error code 10061: No connection could be made because the target machine actively refused it 127.0.0.1:8731.


On 4/27/2012 8:31:59 AM Martin Skov Nielsen said ..
Thx - this one really got me under way :-D

Really easy to break a part and use!