Note: To successfully share the same code (consuming the WCF Azure web service), on the Desktop platform you must "Add Service Reference", click Advanced and ensure "Generate asynchronous operations" is checked; asynchronous is the default for Silverlight and Phone when you Add Service Reference to these projects.
What I am most impressed with is the performance of the Azure Web Service. When I access the link it displays immediately; I'm accustomed to "spin-up" time which has successive access generally fast, but I have never seen this kind of performance accessing a web service!
Most of us are using Rest services (which are very convenient) but in the case of my http://passwordmgr.codeplex.com/ project I am going the WCF road for performance reasons; I want the Phone access to be extremely fast without any additional overhead. Anyone who has created enterprise level applications using WCF services understands the ramifications of this (you have to update any Web References if the interface changes), however since I'm using dependency injection and a data access layer my enterprise application configuration carries very little overhead (as I will demonstrate below).
Setup was only hard because of the dis-information and outdated data that is available when Binging the topic on adding WCF services (particularly for Windows Phone). The following is an updated process as of 2/20/2011.
Creating the service
Add new project - select Cloud
Select Windows Azure Project [OK]
Select WCF Service Web Role [OK]
I renamed the WCFServiceWebRole1 to WCFGwnServiceWebRole, this caused me some issues because I was permitted to successfully launch the web role service directly but once deployed the Azure cloud application would not run, I had to turn on CustomErrors to find out that the rename didn't rename the GwnService.svc class definition (line 4 on the bottom right pane in the image below); once I fixed this the application warned me that I should have 2 instances - I made the change on line 4 of the top right pane in image below.
Publishing the service
This was more challenging then it needed to be perhaps these steps will save you a few hours.
- Right click on the Azure project (not the Web Role) and select Deploy your Windows Azure project to Windows Azure.
- Click Credentials dropdown list and select Add
- Click dropdown list for option 1 (Create or select an existing...) and select <create> and provide a name [OK]
- Select the link on option 2 to Copy the full path
- Click on link to launch Windows Azure Portal
- Select Hosted Services, Storage Accounts & CDN
- Select Manage Certificates
- Click Add Certificate
- Click [Browse] and paste the certificate path and click [Done]
- Cancel the Visual Studio model windows to return to Visual Studio.
Deploy your Service
- Right click on the Azure project (not the Web Role) and select Publish
- I attempted to add a credential but this sent me into a chicken-before-the-egg corner and after I configured the necessary pieces it could not connect to the allocated storage. It is EASIEST if you click the Create Service Package Only radio button and [OK].
- An explorer window will open that will contain the Service package, copy the path to the clipboard
- Go to the Windows Azure portal https://windows.azure.com/
- Create a Storage Account - you'll need this to publish
- Click on Hosted Services in left menu
- Click on New Staging Deployment in top menu
- Provide a Deployment name
- Click [Browse Locally] and paste the path previously saved folder path from the clipboard to select both the Package location and Configuration file. Click [OK] and have patience while it imports and deploys the package to your staging area
At any point after publishing you can click on Hosted Services, select your service and then get the DNS name as shown below - simply add your service name to the end. Note: this name will change everytime you publish which is why configuration needs to be simplified (using dependency injection as shown below)
After the initial publish, successive publishes will be simple - simply right click on the Azure project and pick the Credential configured for this solution and click [OK]
Consuming the newly published Web Service
The following is the test data access layer I created for the Desktop, Silverlight and Windows Phone applications (they all share this code). I added a Web Service Reference being sure to use the same name.
When I got done adding the phone's web reference the auto generated ServiceReferences.ClientConfig was empty (only had a single line for configuration). I found I had to reinstall the Silverlight4_tools.exe and all was well after that. I added Web References to the Silverlight and Desktop applications (changeset 85264 on http://PasswordMgr.CodePlex.com). I plugged in a hook that executes GetData() during the ReadList() command for the Password Manager IF the AppConfig.ServiceAddress is not null (AppConfig is injected in class base via dependency injection).
I had to republish a few times because of the web role rename issue and each time the address changed. To simplify matters I updated the bootstrapper (single location shared by all of the applications in the main app projects) so that it configured the address from a single location (line 134 below); this is the only change I have to make because I programmatically configure the binding and address (lines 24-29 above). With this technique configuration files are no longer required - all I'll have to do is update web references for my data access layer project(s) if the interface changes and I'll be done.
IMPORTANT: because I inject the value into an IAppConfig singleton (line 133 below) it is available throughout the entire application (ClassBase has the unity dependency property IAppConfig, line 13 above, so it is easily available to my data acess layer).
Note: I remarked out line 133 in the changeset because odds are the address will change again and I don't want to introduce a bug that will crash the app for those that might download the source code.
With the above noted configurations I was able to successfully launch and run the Desktop and Phone application and watch the output log display that the contents were successfully returned. Silverlight gave an "attempting to access a service in a cross domain way" error which I resolved by adding a ClientAccessPolicy.xml file per the following LINK. With that change, and redeploying the web service, all three platforms successfully ran the code.