Contents
- Introduction
- WCF AJAX Service- Introduction
- Look at our project TweetBL defining simple Business Functionality
- Creating a WCF AJAX Service project (for TweetBL Project's Business Functionality)
- Running the default WCF AJAX Service project
- Building WCF AJAX Service project (for TweetBL Project's Business Functionality)
- Running the WCF AJAX Service project (now with our Business Code)
- Switching from JSON to XML for WCF AJAX Web Service
- Creating WCF AJAX Web Service Client
- Testing WCF AJAX Web Service using our Service Client
- Final Thoughts
Introduction
In this article, we will be looking into creating a WCF AJAX Web Service!
I would recommend giving a quick read to this article to get a brush up on basic WCF details.
I will focus on covering WCF AJAX Service related topics in this article and will not divulge into basic WCF related details example - explaining Operation Contracts. The above linked article explains these topics.
We will be using a simple business layer project called TweetBL
in this article to start things up. During the course of this article, we will expose the business functionality of TweetBL
as a WCF AJAX Web Service.
We will be focusing on churning out a WCF AJAX Web service in this article and I have tried my best to keep it as simple as one can.
Following the KISS concept: "Keep it Simple Stupid."
So let's get the ball rolling...
WCF AJAX Service - Introduction
"Asynchronous JavaScript and XML" is a web development technique that supports creating an interactive website with rich client presentation. AJAX facilitates retrieval of data from a server: asynchronously - what this means is AJAX invokes a new request (for data) without disrupting the client's current view!
AJAX enables us to fetch Server-Side content dynamically and makes it look like client-side dynamic content... the user is subjected to no interruptions whatsoever! while AJAX does this dynamic server-side content fetching under the covers. Once this fetching of data form server is done, client's current view is updated with the retrieved data.
Finally, the main purpose of AJAX is to improve speed, usability and performance of a web application.
A business example could be a Rating Functionality on a Web Page. When a user rates something - their rating of say 5 is stored into the database without the need to refresh or reload the web page. The user just selects the 5 stars and goes on by his/her business on the web page whilst AJAX works on the background vigorously to please its masters by doing the needful.
Lastly, AJAX employs the below listed technologies (but is not limited too) and mechanisms to make a developers life easier:
- JavaScript
- XML
- Asynchronous requests to server
"WCF AJAX Web Service"
Windows Communication Framework (WCF) is as interesting as the Marvel Universe! no kidding.
WCF is a framework which supports message-based communication between Client and server.
WCF is highly configurable... We will leverage this trait of WCF by employing EnableWebScript
behaviour configuration option!
EnableWebScript
behaviour provides for XML and/or JSON serialization instead of using the traditional SOAP envelopes! It also creates a default JavaScript Proxy (this default JavaScipt Proxy includes client code for sending and receiving data between the client and server along with information regarding the required transport objects to exchange data) for each AJAX service that is defined... and this generated JavaScipt proxy can be consumed by any web client.
Other important factor is that WCF AJAX service is an example of Web API Web Service. This is because WCF AJAX service uses HTTP standards to send and receive data and does not rely on WSDL which the traditional WCF SOAP over HTTP services use. We will be using multiple HTTP verbs (like Get
/Post
/Delete
) to communicate with the server.
All of the above just by tweaking WCF Configuration!
Finally, AJAX clients are Web pages running JavaScript code and accessing these WCF services using HTTP requests.
We will be developing a WCF AJAX Web Service which will be consumed by a client Web Page running JavaScript via HTTP requests.
Time to roll-up our sleeves and get started!
Look at Our Project TweetBL Defining Simple Business Functionality
We will expose TweetBL projects Business Functionality as a Web Service!
The project that we will be exposing as a Web Service is a simple class library project called TweetBL
. Project TweetBL
represents the business code that has been identified to be made available over the web as a WCF AJAX web service.
TweetBL
project has the following business functionality (methods) that will be exposed as a service. Business functionality methods are:
- Update tweet
- Save/insert a tweet
- Delete a tweet
- Retrieve tweet by id and
- Retrieve all tweets
TweetBL Project:
![TweetBL Project Screen-shot](/KB/WCF/887611/1.png)
Tweet.cs is simply the data class identifying all data members that we have to fetch/update/insert and delete to manage tweets. Think of Model (Data Model).
![Tweet.cs Class Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
ManageTweet.cs is the class that houses the business methods that do all the necessary processing on the Tweet Data to manage and maintain it. Note: There is a bit of housekeeping code as well because we are not using an actual database to keep things fairly simple.
![ManageTweet.cs Class Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Creating a WCF AJAX Service Project (for TweetBL Project's Business Functionality)
Now that we have had a quick trip of our TweetBL
Project, it is time to jump into some real code... Let us start by adding a new project called Tweet.WCFService.AJAX
which will be our WCF AJAX Service project.
![Adding Tweet.WCFService.AJAX Project Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Select the Empty option and nothing else.
![Adding Tweet.WCFService.AJAX Empty Project Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX Project added Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
The above step has created an empty ASP.NET Web Application for us!
Now, we will add a WCF AJAX Service to Tweet.WCFService.AJAX
project. Go to add new item (on Tweet.WCFService.AJAX
project) and follow the screen-shot below:
![Tweet.WCFService.AJAX Adding New Item Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX Added New AJAX Service Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
As soon as we add the AJAX service, a few changes were made to our project.
A few references and libraries from .NET were added to our project. We will cover a few interesting bits!
Our Web.config file has also been modified! Let us have a look at that...
![Tweet.WCFService.AJAX Web.Config Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
A behaviour has been added to our Web.config file (above screen-shot) to enable Web Scripting for our project. An <endpointBehavior>
has been added which will enable listening of request calls for web services. <enableWebScript />
behaviour maps Operation Contracts to specific URIs. <enableWebScript />
also creates a JavaScript proxy file for us for our services which we will have a look at shortly. <enableWebScript />
also enables a few ways for us to serialize data. We have options between JSON or XML to serialize data. The important thing to note here is that all this is part of Web API.
Notice the binding used "webHttpBinding
". This allows our web service clients to communicate with our service using HTTP get
and post
verbs. Note only the methods decorated with Operation Contract
attribute are exposed as services.
Along with the above changes, we are also provided with a template file for our TweetService.svc class.
![Tweet.WCFService.AJAX TweetService.svc templete file Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Here unlike: SOAP over HTTP Web Services, we do not have an interface
class. The Service Contract
and Operation Contract
attributes are directly defined on the class. Also, take a note of AspNetCompatibilityRequirements
attribute: this attribute indicates that this service integrates with the ASP.Net pipeline. Now that we have created a project and have had a quick tour of what we have been given by default to work with, let's start building the real thing!
Running the Default WCF AJAX Service Project
So in our WCF project Tweet.WCFService.AJAX
, let's start things by running the default code that we got after creating the project. This can be done by right clicking on TweetService.svc and selecting view in browser!
![Tweet.WCFService.AJAX TweetService.svc view in browser Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX TweetService.svc default service-run in browser Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Beauty! the auto generated HTML page. Now this is a Web API service so no WSDL is generated!
Of course, we have come this far and there is no harm in testing the default DoWork
method that we saw in class TweetService.svc. To do this, all we have to do is add a new attribute to the DoWork
Method. The new attribute is WebGet
shown below in the screen-shot.
![Tweet.WCFService.AJAX TweetService.svc WebGet attribute Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Naturally, you would want to know what WebGet
attribute does? Basically, WebGet
attribute exposes operations (decorated with it) using the GET
verb! Now our DoWork
service is directly accessible via a Web browser by typing the URI to the service (TweetService.svc in our case) followed by the method/operation name (DoWork
in our case) into the address bar. This is what we will do next.
After adding this new attribute, again, we go right click on TweetService.svc and select view in browser. Type in method DoWork
at the end of the path... and hit enter.
![Tweet.WCFService.AJAX TweetService.svc DoWork URI Call Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
the fruits of our labour...
![Tweet.WCFService.AJAX TweetService.svc DoWork URI Call result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
{"d":null}
is the response that we got back by making a call to DoWork
service operation. This is in JSON format.
Calling AJAX Services is this simple! We start with the service file name in this case TweetService.svc followed by the name of the method, in this case DoWork
. Remember we have decorated DoWork
with the WebGet
attribute which enables the operation to be accessible via the HTTP get
request.
The format of the returned result for DoWork
has to do with the default generated JavaScript Proxy
class for our WCF Service. <enableWebScript />
helps generate this default proxy. The return result is an object that has come back with a "d
" parameter. This is also done on purpose to work with above mentioned proxy.
If you wish to look at this default generated proxy - all you have to do is append the service file name TweetService.svc with a js as shown in the screen-shot below:
![Tweet.WCFService.AJAX Default Generated Proxy Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Some interesting things regarding the default proxy - Apart from the apparent constructor at the start of the proxy file and from the boiler plate code - Towards the bottom of the file, we find the following interesting bits:
Highlighted is the exact URL to access our AJAX web service...
![Default Generated Proxy Web Service address Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Highlighted is the function definition of our default DoWork
method...
![Default Generated Proxy Web Service DoWork Operation Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
So, including this script in our web page will enable us to connect to our service and call our DoWork
method using JavaScript!
The last interesting bit is the function definition to call our method DoWork
.
![Default Generated Proxy Web Service DoWork Function Call Definition Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
So, the above screen-shot indicates that a call to DoWork
method takes 3 arguments.
onSuccess
: This is a handler that will execute once the AJAX service call has completed successfully. Any data passed on by the web method call will be passed onto this onSuccess
function. onFailed
: This is a handler that will execute if the AJAX service call has failed due to some reason. Any error data passed back will be passed onto this onFailed
function. userContext
: This allows to pass User related data.
Now that we have created a WCF AJAX Web Service project and have spent a fair bit of time running and understanding it... it is now time for us to introduce some relevant business code in our WCF AJAX Service project: Tweet.WCFService.AJAX
. This is done in the following section.
Building WCF AJAX Service Project (for TweetBL Project's Business Functionality)
Time to build our real AJAX Service and remove DoWork
method! Let us tap into TweetBL Project - ManageTweet.cs: this class has all the business code that we would need to manage a Tweet. We will expose all these methods as an AJAX Web Service.
![Tweet.WCFService.AJAX Project TweetService.svc after Business Code added Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
In TweetService.svc of Tweet.WCFService.AJAX
project, we have included a reference to ManageTweet.cs of TweetBL
Project and as demonstrated in the screen-shot above, all we do is pass the call that we receive for any TweetService.svc method to ManageTweet
class methods to do the actual work.
Simply put, all we do in our service
class is call the business class to do the actual job.
Running the WCF AJAX Service Project (now with our Business Code)
So now we are ready - to actually run our Tweet Service! It is not going to be much different... but yes, there are a few extra steps that we will need to follow to run some of the methods! which do not implement the GET
verb (WebGet
attribute) but implement WebInvoke
attribute. The ones pointed out (in TweetService.svc) below:
![Tweet.WCFService.AJAX Project TweetService.svc WebInvoke Methods Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Trust me, it is good fun...
Testing GetTweets() Method: Follow the steps highlighted in screen-shots below: Run the service:
![Tweet.WCFService.AJAX Project TweetService.svc GetTweets Method Call Running Service Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Type the method name GetTweets
:
![Tweet.WCFService.AJAX Project TweetService.svc GetTweets Method Call Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
GetTweets
method result (unformatted):
![Tweet.WCFService.AJAX Project TweetService.svc GetTweets Method unformated result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Notice k__BackingField
appended to each of our Tweet
property... this is because we have not marked our Tweet
Class (TweetBL
Project) with DataContract
attribute and its fields with the DataMember
attribute.
![TweetBL Project Tweet.cs DataMember Attribute Missing Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Quick refresher: Data Contracts defines the type and the format of data that will be sent out and received by the web service operations. Data Member attribute is applied to the fields of the DataContract
class that are to be serialized.
I have described a fair bit about WCF contracts in one of my previous articles, the relevant section can be found here.
Applying the attributes to Tweet.cs:
![TweetBL Project Tweet.cs DataMember Attribute Added Serilaization Namespace missing Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Ouch! the red squiggly lines.. ahh.. This just indicates that you do not have reference to the "Serialization
" assembly in your TweetBL
Project!
namespace TweetBL
{
using System;
using System.Runtime.Serialization;
.... remaining code...
Let us quickly add reference to "Serialization
" assembly:
![TweetBL Project Tweet.cs Serilaization reference-1 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![TweetBL Project Tweet.cs Serilaization reference-2 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
and the world is a happy place again...
![TweetBL Project Tweet.cs Serilaization reference-2 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Running TweetService.svc again... we get the following result: k__BackingField
is no longer appended.
![Tweet.WCFService.AJAX Project TweetService.svc GetTweets Method formatted result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Let's run GetTweetById()
method. This method is decorated with WebGet
attribute, but it also expects a Parameter! of type int to be passed in as well... sweet...
![Tweet.WCFService.AJAX Project TweetService.svc GetTweetById Method Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Running the TweetService.svc and invoking GetTweetById
method without passing an int
parameter will yield the following result of NULL
:
![Tweet.WCFService.AJAX Project TweetService.svc GetTweetById Method No Param Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
We got null
because, WCF tried its best to match the needed parameter (in this case int
) and when it failed, it assigned the default value for the required parameter. So, in this case for int
- WCF assigned it a value of 0
. Stating the obvious here, we do not have a record with id = 0
so, null
is returned.
All we need to do is pass on the needed parameter (check below):
![Tweet.WCFService.AJAX Project TweetService.svc GetTweetById Method with Param Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Note: The parameter name in the get
URI should match the parameter name declared on the method!
![Tweet.WCFService.AJAX Project TweetService.svc GetTweetById Method TwwetId Param Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
So, this was a simple demonstration of how to run a service operation/method that is decorated with WebGet
attribute!
It's time to look at the other operations that are decorated with WebInvoke
attributes TweetService.svc class...
![Tweet.WCFService.AJAX Project TweetService.svc WebInvoke Methods Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
The key difference between WebGet
and WebInvoke
attribute is that it uses a POST
verb instead of a GET
verb that WebGet
uses.
Why use WebInvoke
? Well, the WebInvoke
attribute exposes service operations/methods using other HTTP verbs such as POST
, PUT
, and DELETE
. These operations are meant to MODIFY
a resource; therefore, the WebInvoke
attribute is used to make modifications to a resource. Note: The default option is POST
but you can change it by setting the Method Property of the WebInvoke
attribute. Demonstrated below:
[OperationContract]
[WebInvoke(Method = "PUT")]
public void PutQuestion(int id, Question question)
{
}
Note* We will stick to default POST
in this article.
Another interesting thing to keep in mind is that all web browsers are optimised to cater for GET
verb requests. They cache the result of Get
requests and any-time the browser is refreshed, the results are drawn back from browser cache instead of making a trip to the Web Server.
So, for obvious reasons, now when you are performing create
, update
or delete
operations, you do not want browsers to cache the results of these operations! So, we use a different verb like Put
, Post
and others to indicate that we do not wish to cache the result of these operations and will always like to do a refresh on data once the Put
, Post
operation has been completed successfully. It is a Win Win!
Now, moving on... if we try to run the WebInvoke
decorated operations, the way we invoked operations decorated with WebGet
attribute, we get the following result:
![Tweet.WCFService.AJAX Project TweetService.svc WebInvoke Method run Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
We get Method not allowed message because we specified WebInvoke
attribute for CreateTweet
operation.
The question we are asking now is... How do we test our WebInvoke method CreateTweet? The simple answer is we use "POSTMAN".
POSTMAN: is a plugin for Google Chrome that allows us to create HTTP Get
/Put
/Post
/Delete
requests! Just what we need!
There are answers to questions that are to be found... well this question is not one of them. :) thanks to Google.
![POSTMAN Search Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Without further ado, add it to the browser...
![POSTMAN Adding Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Running POSTMAN is as simple, open new tab on Chrome, click on the app grid and there you should find it.
![POSTMAN App Grid Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![POSTMAN running Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Enter the URL for our local CreateTweet
operation. ![POSTMAN Tweet.WCFService.AJAX Project TweetService.svc CreateTweet URL Method run Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Remember it is a WebInvoke
method, so change the option to POST
.
![POSTMAN Tweet.WCFService.AJAX Project TweetService.svc CreateTweet URL POST Option run Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Click on the Header Button! We want to indicate that we will be sending JSON formatted data to server:
![POSTMAN Header 1 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Let's put in the Header and Value... so that our request is crystal clear to the server!
![POSTMAN Header Values Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Switch to RAW Mode and select JSON..
![POSTMAN RAW Mode Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Time for some action! We will send in a specifically formatted request... in this case, it will be a Tweet
Object - with all its 3 properties.
![POSTMAN CreateTweet Call JSON body Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Flashback the 3 Tweet
Properties! - Tweet.cs (in TweetBL
project)
![POSTMAN Tweet.cs body Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Time to click SEND.
![POSTMAN CreateTweet Send button Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Ouch, that hurt...
![POSTMAN Error Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
We got an error back - WCF passed us some options that we can use to get more details regarding the issue that occurred on the server! Example: In the above screen-shot, we are advised to turn on includeExceptionDetailInFaults
so let's do that...
In our Tweet.WCFService.AJAX
project, let's update Web.config file to set includeExceptionDetailInFaults
option to true
. This is a debug option and should be leveraged only while development makes sure you turn it to off (to false
) once the service is about to be deployed.
// Let us add the following service behaviour to our Web.Config file
<serviceBehaviors>
<behavior name="reportIssues">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
reportIssues
is the name we have given to the behaviour. includeExceptionDetailInFaults
has been set to true
to indicate we would like exception details passed to the client that have occurred on the server. Note* includeExceptionDetailInFaults
is set under the serviceDebug
element.
Now, we need to associate this new behaviour with our service.
<service name="Tweet.WCFService.AJAX.TweetService"
behaviorConfiguration="reportIssues" >
<endpoint
address=""
behaviorConfiguration =
"Tweet.WCFService.AJAX.TweetServiceAspNetAjaxBehavior"
binding="webHttpBinding"
contract="Tweet.WCFService.AJAX.TweetService" />
</service>
Here is the screen-shot of the Web.config file after making the above mentioned changes.
![Web.Config Updated Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Web.config has been updated. Let's run the service again.
![POSTMAN Error Take 2Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Now, we get the above highlighted information back!
The server is complaining that the object reference is not set to an instance of an object...
I must admit this is not that helpful but we have to work with what we have.. and as I have burned myself before with this issue, I can tell you what the problem is!
Screen-shot of CreateTweet
Operation (Notice: the Parameter Name):
![POSTMAN CreateTweet Operation Parameter Name Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Screen-Shot of our JSON request message (Notice: the name of our Tweet
Object):
![POSTMAN CreateTweet JSON request Object Name Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
and bang, it is the parameter name mismatch! issue. Let us correct the object name in our json request and try again...
![POSTMAN CreateTweet JSON request Object Corrected Name Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
and there... the operation call was successful! Operation returned null
because it has return type of void
.
![POSTMAN CreateTweet JSON request success! Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Running the GetTweets
method to establish that the new record was successfully inserted and there... highlighted below are the fruits of our labour.
![POSTMAN GetTweets confirming CreateTweet success! Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
I hope this was simple enough to be followed. You are welcome to test all the other Service operations using POSTMAN
.
I will leave the remaining service operations for you to play with on your own. Screen-shots of my unit testing of UpdateTweet
and DeleteTweet
Operations are given below.
UpdateTweet
Operation (Remember to pass in the Id
for the Tweet
that is to be updated):
![POSTMAN UpdateTweet Operation](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
GetTweets
method call after UpdateTweet
operation:
![POSTMAN UpdateTweet Operation result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
DeleteTweet Operation (Notice: our request JSON Object):
![POSTMAN DeleteTweet Operation](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
GetTweets
method call after DeleteTweet
operation: Tweet
with Id = 5
was not returned! as it has been deleted.
![POSTMAN DeleteTweet Operation result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Switching from JSON to XML for WCF AJAX Web Service
The default set-up for WCF AJAX Web Services expects to send and receive data in JSON format. The main reason is because WCF AJAX Web services are geared to using JavaScript and JavaScript prefers and works very well with JSON. We can change this to say XML by following the steps below:
[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Xml)]
public IList<Tweet> GetTweets()
{
return _businessLayerTweetService.GetTweets();
}
Re-running the GetTweets
Operation: ![GetTweets XML result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
The result is in XML format!
Creating WCF AJAX Web Service Client
Postman was good for some quick unit testing. Now it's time to build our own web service client. Let us have a quick re-look at the generated JavaScipt library for our service. We have all the Tweet Operation(s) that we defined available now. ![JavaScript Service Proxy.. re-generated Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Also, to look at the debug feature... you can go to the following URL. This file basically will help us with code completion in Visual Studio while we are working on the test client (web service client). ![JavaScript Service Debug Proxy Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Now, let us move on to writing a proper client for our service. WCF AJAX Web Service are really developed to work well with HTML-JavaScript based clients. Developing HTML-JavaScript based clients is much easier because we do not have to worry about serialization and de-serialization among many other factors. This all is done for us by default. If for some reason we choose to write our own standalone client (we can choose any client side technology), then we will be responsible for creation of request and response objects, serializing and de-serializing the request-response objects ourselves and many other such requirements would have to catered by us! This is because there is No WSDL generated for WCF AJAX Web Service. To keep things simple here, we will develop a simple HTML-JavaScript based client for our Tweet
Service! We will be using the default generated JavaScript proxy class in our client web page. We need to add a Web Form, go to add new item in Tweet.WCFService.AJAX
Project and select Web Form.
![Tweet.WCFService.AJAX Project Adding Client Web Form Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
TweetClient.aspx has been added to the Project!
![Tweet.WCFService.AJAX Project TweetClient.aspx Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX Project TweetClient.aspx Default Code Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
We will add a ScriptManager
to TweetClient.aspx: This ScriptManager
will be responsible for downloading the default JavaScript Proxy
class that was generated for our TweetService
! To do this, we need to provide a Service Reference (which will be declared inside a Service
tag) to ScriptManager
. The reference will require us to pass it a Path
to our Tweet
Service.
// Tweet.WCFService.AJAX Project
// TweetClient.aspx
//
// ~: the tilde refers to the current application
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Services>
<asp:ServiceReference Path="~/TweetService.svc" />
</Services>
</asp:ScriptManager>
<div>
</div>
</form>
</body>
TweetClient.aspx:
![Tweet.WCFService.AJAX Project TweetClient.aspx with Script Manager Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
So, now the Script Manger will include the generated JavaScript Proxy file for Tweet
Service and it will also include some other required libraries that this web page (TweetClient.aspx) would need to make use of the TweetService Proxy
class under the covers.
This is it... we can start writing JavaScript to call our TweetService
methods.
We will do the following in TweetClient.aspx's Script
tag:
- Create a tweet
- Update a tweet
- Delete a tweet
- Retrieve all tweets
Screen-Shot of TweetClient.aspx Script
tag:
![Tweet.WCFService.AJAX Project TweetClient.aspx Script Tag Code Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Time to test our web page. We will do this in the next section.
Testing WCF AJAX Web Service using our Service Client
Well, so here we are! Finally almost there... follow the Screen-shots below to run the test:
![Tweet.WCFService.AJAX Project TweetService.svc run the service Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX Project TweetService.svc Service running Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Type in TweetClient.aspx...
![Tweet.WCFService.AJAX Project TweetClient.aspx typed in Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Fruits of our labour! First the Success Alert Message of CreateTweet
is displayed!
![Tweet.WCFService.AJAX Project CreateTweet Alert Success Message Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
and now the final GetTweets
result!
![Tweet.WCFService.AJAX Project TweetClient.aspx Final Get Result Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
The last tweet (Id = 5
) is the record that we added through TweetClient.aspx Script
tag!
Interesting bit
Quick inspection of the page will reveal that a few other Script
tags were added to our HTML page which were not added by us!
ScriptManager
added them for us.
Example: Web Resource and Script Resource were added by the ScriptManager
. These resources take charge of serialization and de-serialization activities among many others that they perform under the covers for WCF AJAX Web Services!
![Tweet.WCFService.AJAX Project TweetClient.aspx Inspect Element Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX Project TweetClient.aspx Inspect Element Detail Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Important Note* Calls to Create/Update/Delete and get will not be executed in synchronous order.. any of them can be called before or after. They are executed asynchronously!
I know - I have stated the obvious! AJAX rings a bell! :)
Quick look at DeleteTweet
method in TweetClient.aspx: I have commented the code for Create
and Update Tweet
as I just want to focus on Delete
and Get
.
![Tweet.WCFService.AJAX Project TweetClient.aspx DeleteTweet Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Running the test for DeleteTweet
:
![Tweet.WCFService.AJAX Project TweetClient.aspx DeleteTweet Result 1 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
![Tweet.WCFService.AJAX Project TweetClient.aspx DeleteTweet Result Get Call Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Fortunately, for me DeleteTweet
was called before making the call to GetTweets
! Tweet
with Id = 2
has been successfully deleted.
Quick look at UpdateTweet
method in TweetClient.aspx: I have commented the code for Create
and Delete Tweet
as I just want to focus on Update
and Get
.
![Tweet.WCFService.AJAX Project TweetClient.aspx UpdateTweet Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Running the test for UpdateTweet
:
![Tweet.WCFService.AJAX Project TweetClient.aspx UpdateTweet Result 1 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Fortunately, this time for me UpdateTweet
was called after making the call to GetTweets
! Tweet
with Id = 1
has been successfully updated, but the data retrieved does not reflect the change! This is AJAX for you.
Refreshing the page will reflect the change: Note* It will also execute the UpdateTweet
call again! but it would be harmless for us. Usually in production code, we have validations which will stop this second update.
![Tweet.WCFService.AJAX Project TweetClient.aspx UpdateTweet Result 1 Screen-shot](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
I have left Update
and Delete Tweet
Code commented in TweetClient.aspx.
...and we are DONE!
Final Thoughts
Here is an article on WCF Web Service! written by me. It is a simple demo demonstrating the power and simplicity of WCF.
It's time for me to sign off. Feel free to ask questions, provide feedback and everything in between as I am on the same boat with you. P.S.: The Boat is called "Burn and Learn".
History
- 14th March, 2015: Version 1 submitted