Using WCF on Windows Phone 7: Walk-through


 

Windows Phone 7 and WCF: a great combination, but can be tricky to get going. Here is how I did it.

Internally at Microsoft there has been quite a bit of interest with developers wanting to produce WCF (Windows Communication Framework) applications for Windows Phone 7. Bizarrely I turned out to be one of them, despite having no clue about WCF a month ago. While I can hardly be called an expert in the subject or even an intermediate WCF user, I did get everything working. However lots of internal folks failed, and I am guessing more than a few external folks will also, so here is a quick run-through of creating a WCF Stand Alone Host application on the PC and a WCF Client on the phone. I did this with the RTM tools for this, but the same steps should also work fine on the beta release (though not the older CTP). This might not work on Visual Studio Express though, I don’t have that to test on, sorry, I use Ultimate and I know VS Pro works too.

Making a WCF Server (from a WinForms app)

In Visual Studio do File / New Project / Visual C# / Windows / Windows Forms Application and name it WCFSimpleHost.

Choose Project / Properties and on the Application tab change Target Framework from “.NET Framework 4 Client Profile” to “.Net Framework 4” and say Yes to the confirmation dialog. This is required as we need access to the next assembly:

Project /Add References /  .Net /  System.ServiceModel (ensure it is version 4.0.0.0)

Project / Add New Item / Visual C# Items / Interface / ITest.cs

Should look like this:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;

 

namespace WCFSimpleHost

{

    [ServiceContract]

    interface ITest

    {

        [OperationContract]

        string Add(int x, int y);

    }

}

 

A trivial interface that adds two integers and returns the result as a string. Why not? With the interface defined, lets implement it:

Project / Add / New Item / Visual C# Items / Class / Test.cs looks like this:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace WCFSimpleHost

{

    class Test : ITest

    {

        public string Add(int x, int y)

        {

            int total = x + y;

            return total.ToString();

        }

    }

}

 

From Solution Explorer double click on Form1.cs and the Designer will open. Double-click on the Form and in the Form1_Load method add

using System.ServiceModel;

using System.ServiceModel.Description;

 

 

and this:

        private ServiceHost HostProxy;

 

        private void Form1_Load(object sender, EventArgs e)

        {

            string address = “http://localhost:8001/test”;

            HostProxy = new ServiceHost(typeof(Test), new Uri(address));

 

            // Enable metadata publishing.

            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();

            smb.HttpGetEnabled = true;

            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;

            HostProxy.Description.Behaviors.Add(smb);

 

            // Open the ServiceHost to start listening for messages. Since

            // no endpoints are explicitly configured, the runtime will create

            // one endpoint per base address for each service contract implemented

            // by the service.

            try

            {

                HostProxy.Open();

                MessageBox.Show(“The service is ready at “ + address);

            }

            catch (AddressAccessDeniedException)

            {

                MessageBox.Show(“You need to reserve the address for this service”);

                HostProxy = null;

            }

            catch (AddressAlreadyInUseException)

            {

                MessageBox.Show(“Something else is already using this address”);

                HostProxy = null;

            }

            catch (Exception ex)

            {

                MessageBox.Show(“Something bad happened on startup: “ + ex.Message);

                HostProxy = null;

            }

        }

 

(By the way I didn’t make this up, I stole it from http://msdn.microsoft.com/en-us/library/ms731758.aspx “How to: Host a WCF Service in a Managed Application”)

If you Build this it should be ok. If you Run it you will get the AddressAccessDeniedException message. Exit the app, then open a CMD window as Administrator and type

netsh http add urlacl url=http://+:8001/test user=Everyone

(I got this from http://msdn.microsoft.com/en-us/library/ms733768.aspx : if you are running something older than Vista you have lost my respect and you’ll need to read the article and take different steps). Note the port number and the Uri must match the one in your code, and a tighter ACL list than “Everyone” would be advised if you are running this on a network with people you don’t entirely trust. As I share my home network with my wife, my Sonos and my TiVo, that isn’t an issue for me.

Now run the application and you should get the success message, click on OK and leave the application running. To check it works, fire up a web browser and enter an URL such as

http://localhost:8001/test

and you should see an HTML page showing “Test Service”. However ignore the contents of it, it doesn’t quite apply to Silverlight for the Phone.

Client Side

Fire up another instance of Visual Studio, it makes things a lot easier to use a separate instance and a separate project for Client and Server. Do File/New/Project /Visual C#/Silverlight for Windows Phone/Windows Phone Application and call it WCFSimpleClient.

Project / Add Service Reference and enter the Uri of the service, in our case http://localhost:8001/test and click Go. Assuming you left the server exe running from above, it will show you the Test contract and class. Change the Namespace to TestService and click on the Advanced… button. I recommend changing Collection type: to System.Array and unchecking “Reuse types in Referenced Assemblies”. I don’t have a specific reason for this, except that others have recommended it and it works for me. Click OK from the Settings dialog and OK from the Add Service dialog. This will generate a new item in the Project under Service References called TestService.

Create a Button in the middle of the design surface and double-click on it. Add this:

using WCFSimpleClient.TestService;

using System.Diagnostics;

using System.ServiceModel;

 

And this:

        private TestClient client;

 

        private void button1_Click(object sender, RoutedEventArgs e)

        {

            if (client == null)

            {

                client = new TestClient(new System.ServiceModel.BasicHttpBinding(), new EndpointAddress(“http://localhost:8001/test”));

 

                client.AddCompleted += new EventHandler<AddCompletedEventArgs>(client_AddCompleted);

            }

 

            client.AddAsync(30, 12);

        }

 

        void client_AddCompleted(object sender, AddCompletedEventArgs e)

        {

            if (e.Error==null)

            {

                Debug.WriteLine(“The answer is {0}”, e.Result);

            }

        }

 

Then F5 to build and run this under the emulator or a tethered device. Click the button and look in the Output window: you should see the result.

WCF from Silverlight is all asynchronous, and this took some getting used to for me. Getting out arguments and error checking is interesting, you can see the beginnings of this in the example. The key is to always have a xxxCompleted event handler defined, even if it does nothing, so that if the server goes away your app doesn’t too.

WCF Untethered

So now it is time to try this untethered (assuming you have an actual device). Be sure to set up wifi on the phone for your home network, then change the code on the client to be something like

string address = “http://mymachinename:8001/test”;

(no server-side changes required). I’ll spare you the suspense but it won’t work. Took me hours to figure this out, but the problem is the Windows Firewall blocks the request from the phone, and the solution is not to add your WCF server exe to the exception list: instead add the port number (8001 in this case) to the Inbound exception list, over TCP. Now it should work, you can verify by firing up the browser on the phone and entering the http address which should get you the html test page.

Note that if you are at work and running on a Active Directory Domain then this might not work untethered: I know it doesn’t here at Microsoft, likely due to some combination of IPSec, WiFi security and not using FQDN. Good luck with that.

Note that every time you change the exported interface in (ITest.cs) you must re-run the server and in the client project right click on the TestService icon and “Update Service Reference” then rebuild the client app. (Once you ship WCF has some versioning attributes you can use to keep old clients working against newer servers).

More WCF Stuff

There are lots of other things that you might need to do with your WCF app but I probably can’t help you with, as I am a newbie to this myself, plus feature-wise my requirements are pretty simple. I’d like to point you to some docs on the differences between WCF on desktop  Silverlight and WCF on the phone, but I haven’t found any yet. Things that you might need to know about that I can’t help you with include:

·         Security

·         Moving your WCF server to the real internet from your home LAN

·         Other WCF binding methods

However hopefully there is enough information here to get you going, and to at least prove that WCF on Windows Phone 7 is possible. And fun actually. Did I say that?

Comments (17)

  1. Catto says:

    Hey Now,

    Great Post!

    Thx 4 the info,

    Catto

  2. Fredrik says:

    Great walkthrough, really straight forward!! Way to go!!

  3. Steve says:

    Good overview.  I'm doing something very similar, but have been unable to figure out how to handle the client when the server is unavailable.  With asynchronous operation, I can't seem to figure out a way to catch exceptions thrown in this case.  And the exception is not what I would expect:  In the generated reference.cs file, the EndAdd function would get a null object reference and throw an exception.  Unfortunately, even the App.cs unhandled exception routine doesn't catch this.

    Have any thoughts on this?

    Steve

  4. Andy-Pennell says:

    Steve: the debugger will always stop on those exceptions in the generated file, for some reason. However if you F5 then it will be turned into an exception in the caller: see the (if e.Error==null) clause in the xxCompleted method above.

    Except on exit: I do get nullrefs on exit occasionally (after I Abort the client) and for those I have no solution.

  5. Tamil mannan says:

    This method is not working for Azure…

  6. Andy-Pennell says:

    Sorry Tamil, Azure is something I don't know much about.

  7. Eric says:

    Totally confused? I thought Phone 7 development only works with Visual Studio 2010 express? Please comment

  8. Lars Stolwijk says:

    Perfect example! Really helped me getting started. I just can't figure out why it won't work when I disable wifi, so it has to use 3g. Does anyone got an idea?

  9. Ivan says:

    Hello,  I'm a beginner programmer, I am writing program for C # for the phone 7. I have a problem: I want to create a chat room messages will peredovatsya on Wi-Fi from your phone to your computer. I know that the phone 7 does not support network. But it may have another way? Please show how this works. Thank you. Sorry for my English.

  10. Andy-Pennell says:

    Eric: you can use any Visual Studio SKU to develop phone apps (in C#, VB doesnt work on Express).

    Lars: if your server is on your home network then disabling will indeed stop your phone from seeing the server.

    Ivan: start with my sample here, get that working then expand it to your needs.

  11. Manolya says:

    Hello, I've just started to learn phone 7 developement and have a project on it at the moment. I used your walkthrough. But i want to add an sql connection. How will i add the configuration string to this project. I hope you answer as soon as possible

  12. Andy-Pennell says:

    Manolya: sorry I have no idea. My last work involving SQL was over a decade ago when I worked on the T-SQL debugger.

  13. Jean-Michel says:

    Are you aware of the Discovery feature of WCF 4.0?  I was wondering if it could be used on the phone. That way, the phone would query for the server and if it doesn't find it, would behave accordingly. I am planning a home server solution where the phone would be able to access the home server while it is connected locally on the network.

    I haven't got time to experiment yet, has anyone else done it?

  14. Hum.  The simple host is running but when I try to add the service reference in the silverlight client, it returns an error : Metadata contains a reference that cannot be resolved: 'http://localhost:8001/test?wsdl&#39;.

    The document format is not recognized (the content type is 'text/html; charset=UTF-8').

    Metadata contains a reference that cannot be resolved: 'http://localhost:8001/test&#39;.

    There was no endpoint listening at http://localhost:8001/test 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.

    I have IIS running as well on a Windows 7 64-bit platform.  (I shut off IIS but results are the same).  I just can't seem to get the hang of this.  Any ideas?

  15. Andy-Pennell says:

    SodGuy: try replacing "localhost" with the ip address of your machine: looks like either there is no service there, or it is blocked by something (eg a firewall).

  16. Ömer Evci says:

    Thanks a lot for this article…

  17. Hlatse says:

    Thanks got it working ,if u have a way of using this with a database please let me know Cause i am trying to make two windows phone application talk to one database using WCF the question where do i put the database and where do i put the service ,please advice

Skip to main content