Let's do another example of a JSON WCF Web Service, this time for a 'POST' web service.
Our two examples so far have been for "GET" web services. These are great for loadingdata - calling a web service with a parameter and getting a bunch of data back - but if you want to save data back to a database, you're going to need to send more than just a parameter.
Once again, WCF does most of the work for us, but it's really useful to see a working example for you to adapt for your own projects.
Creating a "POST" WCF Web Service
First, let's create a WCF Web Service which updates an existing [Order] record. Our application will call our web service, telling it the order number and a new shipping address, and the web service will update the relevant SQL Server record.
As before, let's start in the IService1.cs file.
Add the following code, below the existing [OperationContract] statements:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.IO;
namespace JSONWebService {
[ServiceContract]
public interface IService1
{
...
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "updateOrderAddress")]
int UpdateOrderAddress(Stream JSONdataStream);
...
Here, we are defining a UpdateOrderAddress web service which takes a "Stream" as a parameter, and returns an integer.
This return value will be:
0 | If everything was succesful |
-1 | If an exception occurred |
-2 | If the JSON wasn't in the correct format |
-3 | If we couldn't find an [Order] record with the specified ID |
Here's the UpdateOrderAddress function, which we'll now add to the Service1.svc.csfile:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.IO;
using System.Web.Script.Serialization;
namespace JSONWebService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public int UpdateOrderAddress(Stream JSONdataStream)
{
try
{
// Read in our Stream into a string...
StreamReader reader = new StreamReader(JSONdataStream);
string JSONdata = reader.ReadToEnd();
// ..then convert the string into a single "wsOrder" record.
JavaScriptSerializer jss = new JavaScriptSerializer();
wsOrder order = jss.Deserialize<wsOrder>(JSONdata);
if (order == null)
{
// Error: Couldn't deserialize our JSON string into a "wsOrder" object.
return -2;
}
NorthwindDataContext dc = new NorthwindDataContext();
Order currentOrder = dc.Orders.Where(o => o.OrderID == order.OrderID).FirstOrDefault();
if (currentOrder == null)
{
// Couldn't find an [Order] record with this ID
return -3;
}
// Update our SQL Server [Order] record, with our new Shipping Details (send from whatever
// app is calling this web service)
currentOrder.ShipName = order.ShipName;
currentOrder.ShipAddress = order.ShipAddress;
currentOrder.ShipCity = order.ShipCity;
currentOrder.ShipPostalCode = order.ShipPostcode;
dc.SubmitChanges();
return 0; // Success !
}
catch (Exception)
{
return -1;
}
}
That doesn't look too painful, does it?
When we call this POST web service, we'll send it a JSON record as shown below, but converted into a binary Stream:
{
"OrderID":10248,
"ShipName":"Mikes wine shop",
"ShipAddress":"13 Alcohol Street",
"ShipCity":"London",
"ShipPostcode":"SN1 2HS"
}
Notice how the ID of the [Order] record which we're interested in is embedded in this record. Also, note that in our wsOrder class, OrderID is an integer, so we don't wrap the OrderID value in speechmarks. If we did, it would cause an exception when we attempt to convert our binary Stream back into a wsOrder record.
So, how does this web service work?
First, we need to take our binary Stream, and convert it into a string.
StreamReader reader = new StreamReader(JSONdataStream);
string JSONdata = reader.ReadToEnd();
Once it's in this format, we can pass it to the JavaScriptSerializer class, attempt to turn it into a wsOrder record, and check that this conversion was successful (i.e. our JSON was in the correct format).
JavaScriptSerializer jss = new JavaScriptSerializer();
wsOrder order = jss.Deserialize<wsOrder>(JSONdata);
if (order == null)
{
// An error occurred
}
And finally, we connect to our Northwind database, search for a [Order] record with this ID, and if we find it, we'll update it with our new shipping details.
There's just one last change we need to make, to allow the JavaScriptSerializer to work with our wsOrder class. Open up the Order.cs class and add the following line of code, before the class declaration:
namespace JSONWebService
{
[DataContract]
[Serializable]
public class wsOrder
{
[DataMember]
public int OrderID { get; set; }
[DataMember]
public string OrderDate { get; set; }
[DataMember]
public string ShippedDate { get; set; }
...
Okay, let's test this new web service.
Ah.
How the heck can test it ?
We can't exactly type in a URL into our web browser, along with binary data.
Testing a "POST" Web Service
My preferred solution for testing "POST" web services is to use a very simple separate ASP.Net project.
The following ASP.Net project contains a single webpage (shown in the screenshot below), which lets us type in a web service URL, plus some data to send it to. It'll call the web service, and display any results it gets back.
Here's how to test your POST Web Service, step-by-step.
1. Make sure your JSONWebService project is running in Debug mode.
2. Using the link above, download the TestPOSTWebService project to your computer.
3. Open the TestPOSTWebService project in a new instance of Visual Studio, then build & run it.
4. In the "URL of POST Web Service" textbox, cut'n'paste the URL of yourJSONWebService updateOrderAddress web service:
http://localhost:15021/Service1.svc/updateOrderAddress
5. In the "JSON to send to Web Service" textbox, cut'n'paste the following JSON:
{
"OrderID":10248,
"ShipName":"Mikes wine shop",
"ShipAddress":"13 Alcohol Street",
"ShipCity":"London",
"ShipPostcode":"SN1 2HS"
}
6. Hit the "Call POST Web Service" button.
If all goes well, you'll receive a result of 0, to say the update was successful.
You could actually add this TestPOSTWebService project to your existingJSONWebService solution, rather than opening it in a separate Visual Studio window. Personally, I prefer running it this way, so that any breakpoints in my JSONWebServiceproject will get hit. It makes it much easier to track down problems.
Let's try introducing an error.
Change the JSON to contain an [Order] ID which doesn't exist, then click on the "Call POST Web Service" button again.
{
"OrderID":100248,
"ShipName":"Mikes wine shop",
"ShipAddress":"13 Alcohol Street",
"ShipCity":"London",
"ShipPostcode":"SN1 2HS"
}
You should now see an return result of -3, which means our web service couldn't find an [Order] record with this ID value.
Testing a "POST" WCF Web Service using Fiddler
Alternatively, you can run GET and POST web services using the free Fiddler tool.
It is thoroughly documented on their own website, but here's what you'd need to know, to call our updateOrderAddress service from Fiddler.
1. Download, install and run Fiddler on your PC.
2. Click on the Composer tab, and in the "Parsed" tab, change the type to "POST", and copy your URL into the textbox.
http://localhost:15021/Service1.svc/updateOrderAddress
3. In the "Request Headers" section, replace any existing text with the following one line:
Content-Type: application/x-www-form-urlencoded
(If you don't do this, Fiddler will try to call your web service with a Content-Type of "text/html", and fail miserably. It took me a while to realise this !)
4. In the "Request Body" section, cut'n'paste your JSON string:
{
"OrderID":10248,
"ShipName":"Mikes wine shop",
"ShipAddress":"13 Alcohol Street",
"ShipCity":"London",
"ShipPostcode":"SN1 2HS"
}
5. And finally, click on the "Execute" button.
Fiddler will then call the web service, and display it's "Inspectors" tab.
At the top of this window, you can see the raw data that was sent to our webservice, and in the bottom, you can see the response that it got back (a "0", if our service was successful, in our case).