WCF Web Services & iOS - Part 1

By Mike Gledhill

Pages:

In this section, we're going to go through the steps required to make a WCF Web Service in Visual Studio 2013 which returns JSON data.
As you'll see, it's quite straight forward if you get all the steps right.

Personally, I found it hard to find one up-to-date resource which would take me through these steps.

Our ultimate goal is to send data from a SQL Server database to an iOS device.
We will create a WCF Web Service to read in data from the SQL Server database, and return it in a generic, non-Microsoft (JSON) format, which the iOS device will be able to understand.

SQL Server, to iOS, via WCF Web Services

This section deals with setting up and testing a very basic WCF Web Service, which returns JSON data, and is ready for us to link to the Northwind SQL Server database in the next section.

To follow this tutorial, you will need the following:

  • A copy of Microsoft Visual Studio 2012 or 2013
    (Older versions should work, with minor alterations though.)

Creating your first WCF Web Service

1. Start Visual Studio
2. Create a new project
Click on File \ New \ Project.
In the New Project window, click on Templates \ Visual C# \ WCF.
We're going to create a .Net Framework 4.5 web service, so make sure this is selected at the top of the dialog.
Select the project type WCF Service Application.
In the Name textbox, type in JSONWebService.
Then click on OK.
Browser list of files, or WCF Test Client
3. Set the project properties
In your Solution Explorer window, right-click on your project name and select "Properties".
Click on the Web tab on the left.
Make sure the "Specific Page" radio button is selected, and that Service1.svc is shown as your specific page.
 
Note: the following step isn't actually needed in your real web service projects, but it will help you follow this tutorial, and use the same URL links.
In the Project Url text box, change the URL to: http://localhost:15021/ and click on the Create Virtual Directory button. Click OK to any confirmation messages which appear.
Project properties
4. Run the project
Click on Debug \ Start Debugging to run this sample project.
You should now see the WCF Test Client dialog, showing a few example web services which Visual Studio has included in your project.
Browser list of files, or WCF Test Client
5. Run one of the sample web services
Visual Studio has provided us a few example web services, so let's see what happens when we run one of them.
Double-click on the GetData() web service, type in a number in the Value column, then hit the "Invoke" button.
The WCF Test Client
In the Response section, you'll see the response which the web service returned for us.
"You entered: 13"

Changing the WCF Web Service to return JSON

So far, all we've done is create a new project in Visual Studio, and check that it all runs okay.
Next, we're going to modify the project so that we can call the services using a URL.
Once we've done this, we'll be able to call the web service, and see it's results, simply by passing in the web service name (e.g. GetData) and our numeric value (e.g. 13) within a URL:
Our modified web service
To do this, we need to make some changes to the sample code. First, we need to change GetData's parameter type from "int" to "string"
Open up the Service1.svc.cs file, and change the "value" parameter to be a string:

public string GetData(string value)
{
    return string.Format("You entered: {0}", value);
}

Now, hop across to the IService1.cs file, and replace the original lines

[OperationContract]
string GetData(int value);

...with this..

[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "getData/{value}")]
string GetData(string value);


The "ResponseFormat" attribute tells WCF that we want our service to return a JSON string. Without this, the web service would return your data in XML format instead.
Note also that we set the "UriTemplate" attribute, to specify that we will always be passing a parameter when we call this URL. So, we've set the UriTemplate as this..

UriTemplate = "getData/{value}"

..as we are going to call this function and always pass it a parameter, like this..

http://localhost:15021/Service1.svc/GetData/13

The BodyStyle setting

Also, you'll notice in that WebInvoke, we've included BodyStyle = WebMessageBodyStyle.Wrapped.
Here's what your JSON output will look like with and without this attribute:
{
    GetDataResult: "You entered: 13"
}
With BodyStyle = WebMessageBodyStyle.Wrapped
"You entered: 13"

 
Without BodyStyle = WebMessageBodyStyle.Wrapped

Most web services don't include this BodyStyle setting, they just return the raw data (shown above, on the right).

Honestly, this is fine, but personally, I prefer to include this setting.
XCode, in particular, sometimes has problems deserializing JSON data if it doesn't start with an element, like the "GetDataResult" above.
 

Changing the web.config file

Now, we need to change our web.config file.
This is the fiddly bit, and you might need to apply different changes if you are using an older version of Visual Studio.
First, we need to add the following <services> tag inside the <serviceModel> tag.

<system.serviceModel>
  <services>
    <service name="JSONWebService.Service1">
      <endpoint address="../Service1.svc"
        binding="webHttpBinding"
        contract="JSONWebService.IService1"
        behaviorConfiguration="webBehaviour" />
    </service>
  </services>

  ...etc...

Do be careful with this bit.
If your project isn't called JSONWebService, then you'll need to change this section (in both places shown above in green) to the name of your project.
 
Next, in the <behaviors> tag, add the following <endpointBehaviors> tag:
(If your web.config file doesn't have a serviceBehaviors section, then you'll need to add these lines aswell.)

<behaviors>
  <serviceBehaviors>
    <behavior>
      <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
      <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
  <endpointBehaviors>
    <behavior name="webBehaviour">
      <webHttp/>
    </behavior>
  </endpointBehaviors>

</behaviors>

One last thing: if you're running this on a PC with 4Gb of memory, WCF might just complain about there not being enough memory.
The error will complain about there being "less than 5% of total memory" available.
If this happens, just add the following chunk to the serviceHostingEnvironment line in your web.config file:

<servicehostingenvironment ...=... minFreeMemoryPercentageToActivateService="0" />

Cross-Origin Resource Sharing (CORS)

Just one more thing.
If you are going to be hosting your web services on a particular domain, but accessing the services from some JavaScript on a different domain, then you need to make a further change to your web.config file.

<system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
      </customHeaders>
    </httpProtocol>

    ...
</system.webServer>

For example, as part of this tutorial, I'm going to deploy a copy of these services onto my www.iNorthwind.com domain.
Here's the URL of one of the JSON web services we'll be discussing later:

http://www.iNorthwind.com/Service1.svc/getAllCustomers

If you click on the link above, your browser will call my iNorthwind services, and show you some JSON data.
No problem.
But if you try to load this JSON data using JavaScript code running in your own domain, or from your localhost domain, perhaps like this...

$.getJSON("http://www.iNorthwind.com/Service1.svc/getAllCustomers", function (data) {
    prompt("Success !");
});

...then it'll fail with a strange error like this:

XMLHttpRequest cannot load http://www.inorthwind.com/Service1.svc/getAllCustomers. No 'Access-Control-Allow-Origin' header is
present on the requested resource. Origin 'http://localhost:63495' is therefore not allowed access.

You aren't allowed to get your JavaScript to call web services on external domains - unless your web.config files contains the settings above.

So, if you think you'll be calling your web services using JavaScript from external domains, add the <httpProtocol> settings shown above.
Otherwise, don't add these settings for the time being, but if your web pages ever start throwing up that error message, remember these settings.
You can always add them to your web service's web.config file later, if you want to.

Testing the services

And that's it.
Let's run the project again.
This time, ignore the WCF Test Client window, and instead, open up a browser, and try running the web service with your own parameters, for example:

http://localhost:15021/Service1.svc/GetData/13
http://localhost:15021/Service1.svc/GetData/SomeNumberOrOther

If you're running the Chrome browser, you'll see the results straightaway:
Our modified web service
However, if you're running Internet Explorer, you'll probably see this instead:
Do you want to save this file?
Annoyingly, Internet Explorer doesn't display JSON data by default, and insists on saving it to an external file.
Thankfully, there's a simple solution to this.
Download and run the .reg file in this .zip file to change the two registry settings on your PC, which will allow IE to automatically display JSON results. Then, close and re-run Internet Explorer, and try the URL again.
Internet Explorer, tamed.
(This excellent fix was take from this Stack Overflow page.)
So, the good news is that we can now call our web services directly from a browser, and instantly see the results. The bad news is that we can no longer use the WCF Test Client, as it doesn't work with JSON/REST services like these.

Summary

Brilliant !
We haven't actually started writing our Northwind web services yet, but at least the pieces are in place for us to begin. (And what you don't realise is that it took me hours of experimenting and Googling to get this far myself !)
In the next section, we'll take this a step further, and get our JSON services to return some database records.
 
This is just the start of our JSON Web Services journey. As you'll see on the following pages, once our SQL Server data is accessible as a JSON service, we can display it web pages, in iPhone apps, or throw in a little CSS and AngularJS to create beautiful Master-View web pages like this:

(You can click here to see how to create this example.).

Disclaimer

You'll notice I'm deliberately not explaining what all of these changes are for, or what they mean. There is a wealth of bulky articles out there to explain all of this (for example, try Googling "web.config endpoints" if you want to understand why we added this change to the web.config file) but my aim is to simply show you how to create a complete, general purpose, reuseable web service project with as little pain as possible.
As you've seen, creating WCF Web Services is dead easy if you get each of the steps right.
Get any of the steps wrong, and you'll soon be wasting hours, trying to get around a variety of weird and wonderful baffling error messages.

This is the article I wish that I'd had, when I faced all of these challenges.
 
< Previous Page
Next Page >

Comments

blog comments powered by Disqus