Tag Archives: Ajax

WCF- Changing Data Contract Names and Namespaces

When posting XML data to a Windows Communication Foundation (WCF) web service1, you need to specify the XML namespace of the data sent in the entity-body of your HTTP POST. This lets WCF know how to deserialize the input you’ve sent. By default, WCF maps the namespace to:

http://schemas.datacontract.org/2004/07/Clr.Namespace

where Clr.Namespace is the namespace of your data contract.2 For example, if my data contract namespace is “RESTful”:

namespace RESTful
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //...

then the namespace to use when consuming this service is:

http://schemas.datacontract.org/2004/07/RESTful

Here’s a code snippet that uses jQuery and Ajax to post a Person to the WCF web service:

        $.ajax({
            type: 'POST',
            data: '<Person xmlns="http://schemas.datacontract.org/2004/07/RESTful">'
                  + '<ArtistID>0</ArtistID>'
                  + '<FirstName>Ella</FirstName>'
                  + '<Grammys>14</Grammys>'
                  + '<LastName>Fitzgerald</LastName>'
                  +'</Person>',
            dataType: 'xml',
            // ...

That’s not a descriptive namespace. Let’s change it to something a bit more informative by specifying a ContractNamespace for our assembly.

[assembly: ContractNamespace("http://schemas.dlwelch.com/JazzService", ClrNamespace = "RESTful")]
namespace RESTful
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //...

Putting this at the assembly level changes the namespace for all data contracts in the RESTful namespace. If we didn’t want to change them all, we could have changed a single contract like this:

namespace RESTful
{
    [DataContract (Namespace="http://schemas.dlwelch.com/JazzService")]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //...

I’m going to leave all of the RESTful data contracts in the same namespace (line 1). And while I’m under the hood, I’m going to change the contract name to something more meaningful (line 4):

[assembly: ContractNamespace("http://schemas.dlwelch.com/JazzService", ClrNamespace = "RESTful")]
namespace RESTful
{
    [DataContract(Name = "Artist")]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //..

Now, when we POST to the service, the request details are a lot nicer:

        $.ajax({
            type: 'POST',
            data: '<Artist xmlns="http://schemas.dlwelch.com/JazzService">'
                  + '<ArtistID>0</ArtistID>'
                  + '<FirstName>Ella</FirstName>'
                  + '<Grammys>14</Grammys>'
                  + '<LastName>Fitzgerald</LastName>'
                  + '</Artist>',
            dataType: 'xml',
            // ...         

My ultimate goal is to create a truly RESTful web service. That’s why I want everything to be self-describing – including the namespace for my data contracts. It also means I’m not interested in the WSDL which is auto-generated by WCF. However, changing the contract names and namespaces has the added bonus of making your WSDL nicer too!

A default WSDL would be similar to this:

<?xml version="1.0" encoding="UTF-8"?>
 <wsdl:definitions name="JazzArtists" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" 
    ... 
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
    xmlns:tns="http://tempuri.org/" 
    ... 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                targetNamespace="http://tempuri.org/">
 <wsdl:types>
  <xsd:schema targetNamespace="http://tempuri.org/Imports">
    <xsd:import namespace="http://tempuri.org/"
         schemaLocation="http://development.dlwelch.com/examples/RestService/JazzArtists.svc?xsd=xsd0"/>
    <xsd:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" 
       schemaLocation="http://development.dlwelch.com/examples/RestService/JazzArtists.svc?xsd=xsd1"/>
    <xsd:import namespace="http://schemas.datacontract.org/2004/07/RestService" 
       schemaLocation="http://development.dlwelch.com/examples/RestService/JazzArtists.svc?xsd=xsd2"/>
   </xsd:schema>
 </wsdl:types>
 <wsdl:message name="IJazzArtists_XMLData_InputMessage">
 <wsdl:part name="parameters" element="tns:XMLData"/>
  ... 
</wsdl:definitions>

There are multiple references to “http://tempuri.org/” in addition to the data contract namespace “http://schemas.datacontract.org/2004/07/RestService”. We’ve already cleaned up the latter (line 15), now let’s get rid of tempuri.org. First, we’ll change the namespace for the service contract:

[ServiceContract ( Namespace = "http://schemas.dlwelch.com/JazzService" )]
public interface IJazzService
{

and then the service implementation:

namespace RESTful
{
    [ServiceBehavior(Namespace = "http://schemas.dlwelch.com/JazzService")]
    public class JazzService : IJazzService
    { 
      //...

Finally, we’ll change the namespace for the binding in the web.config:

  <system.serviceModel>
    <services>
      <service behaviorConfiguration="RESTful.JazzServiceBehavior" name="RESTful.JazzService">
        <endpoint address="" binding="webHttpBinding" 
                             bindingNamespace="http://schemas.dlwelch.com/JazzService" 
                             contract="RESTful.IJazzService" behaviorConfiguration="web">
        </endpoint>
   ...

This gives us WSDL using our custom namespaces instead of the WCF defaults:

<?xml version="1.0" encoding="UTF-8"?>
 <wsdl:definitions name="JazzService" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" 
    ... 
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
    xmlns:tns="http://schemas.dlwelch.com/JazzService" 
    ...
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                targetNamespace="http://schemas.dlwelch.com/JazzService">
  <wsdl:types>
  <xsd:schema targetNamespace="http://schemas.dlwelch.com/JazzService/Imports">
    <xsd:import namespace="http://schemas.dlwelch.com/JazzService" 
         schemaLocation="http://development.dlwelch.com/examples/restful/JazzService.svc?xsd=xsd0"/>
    <xsd:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" 
         schemaLocation="http://development.dlwelch.com/examples/restful/JazzService.svc?xsd=xsd1"/>
  </xsd:schema>
  </wsdl:types>
 <wsdl:message name="IJazzService_GetArtist_InputMessage">
 <wsdl:part name="parameters" element="tns:GetArtist"/>
...
</wsdl:definitions>

I haven’t “switched off” the WSDL for my JazzService even though the service will eventually be RESTful. There’s no harm to ROA by leaving it on. So if someone wants to create a client by importing the WSDL, it’s now available with our nice namespaces.


1. Please see my blog post Creating RESTful WCF Web Services Using Visual Studio 2010 for an example of creating WCF web services.
2. Data Contract Names – http://msdn.microsoft.com/en-us/library/ms731045.aspx

RESTful Web Services for Resource-Oriented Architectures (ROA) – Part 1 – URI

My previous posts on RESTful web services focused on the nuts and bolts of building a WCF web service with Visual Studio 2010 and consuming that service with client side jQuery. Although that service is RESTful to the extent it follows Richardson’s and Ruby’s first rule of thumb for REST services, it is not resource-oriented. “If the HTTP method doesn’t match the method information, the service isn’t RESTful. If the scoping information isn’t in the URI, the service isn’t resource-oriented.” 1

The original web service strictly uses HTTP verbs POST, GET, PUT and DELETE to accomplish create, read, update and delete actions. The URI used when creating a record is identical to the one used for reading information : http://mywebsite/myservices/JazzArtists.svc/artists. The differences are found in the HTTP method and the message body. When reading the artist records, we perform a GET request to the URI with no data in the body. The following Ajax call retrieves all artists:

    $.ajax({
            type: "GET",
            dataType: "json",
            async: true,
            url: 'http://mywebsite/myservices/JazzArtists.svc/artists',
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) {
                     //process return data 
            }
        });

To create a new artist record, we do a POST to the same URI and include the artist data in the message body:

    $.ajax({
            type: 'POST',
            dataType: 'json',
            async: true,
            url: 'http://mywebsite/myservices/JazzArtists.svc/artists',
            contentType: "application/json; charset=utf-8",
            data: '{"PersonObject":{"FirstName":"Shirley","LastName":"Horn","Grammys":9}}',
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) {
                     //process return data
            }
        });

The HTTP method matches the method information. To update this record, a PUT request is made to http://mywebsite/myservices/JazzArtists.svc/artists with the details about which record to update and how in the message body:

var newGrammys = 10;
$.ajax({
            type: 'PUT',
            data: '{"PersonObject":{"FirstName":"Shirley","LastName":"Horn","Grammys":' + newGrammys + '}}',
            dataType: 'json',
            async: true,
            contentType: "application/json; charset=utf-8",
            url: "http://mywebsite/myservices/JazzArtists.svc/artists",
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) {
               //process return data
            }
        });

We could have created a web service that updated the artist records through a GET request that included method information in the URI, for example, a GET to http://mywebsite/myservices/JazzArtists.svc/artists?action=Add&FName=Shirley&LName=Horn&NewGrammys=10. However, this would not have been a RESTful service since the method (action=Add) does not match the HTTP method (GET).

Since the method information matches the HTTP method for each request, my previous service follows Richard’s and Ruby’s first rule of thumb for RESTfulness; but, this service is not resource-oriented. The first problem lies in the PUT and DELETE requests. The scope is not in the URI which breaks the second rule of thumb. Deleting an artist is accomplished by a DELETE request to http://mywebsite/myservices/JazzArtists.svc/artists with the name of the artist to delete (the scope) contained in the message body.

        $.ajax({
            type: 'DELETE',
            data: '{"PersonObject":{{"FirstName":"Shirley","LastName":"Horn","Grammys":0}}',
            dataType: 'json',
            async: true,
            contentType: "application/json; charset=utf-8",
            url: http://mywebsite/myservices/JazzArtists.svc/artists,
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) {
               //process results
            }
        });

My new web service corrects this by including the scope in the URI. A DELETE request made to http://mywebsite/myservices/JazzService.svc/artists/127 will remove record 127 from the target data source.

        $.ajax({
            type: 'DELETE',
            dataType: "xml",
            async: true,
            url: 'http://mywebsite/myservices/JazzService.svc/artists/' + artistId;,
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) { 
                  //process return data
            }
        });

The same modification is made to the PUT method with the edit information included in the body.

var artistId=127;
$.ajax({
            type: 'PUT',
            data: '<Person xmlns="http://schemas.datacontract.org/2004/07/RESTful" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">'
                  + '<ArtistID>0</ArtistID>'
                  + '<FirstName>Ella</FirstName>'
                  + '<Grammys>14</Grammys>'
                  + '<LastName>Fitzgerald</LastName>'
                  + '</Person>',
            dataType: 'xml',
            async: true,
            contentType: "text/xml",
            processData: false,
            url: 'http://mywebsite/myservices/JazzService.svc/artists/' + artistId,
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) {
                //process return data
            }
        });

Notice that the real artistId is not included in the message body, only in the URI.

We can see the more RESTful, resource-oriented nature of the new service by inspecting its contracts:


    [DataContract]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }

        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public int Grammys { get; set; }

        public Person(int artistid, string firstName, string lastName, int grammys)
        {
            this.ArtistID = artistid;
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Grammys = grammys;
        }

    }
    [ServiceContract]
    public interface IJazzService
    {
        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "artists/{id}")]
        Person GetArtist(string id);

        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "artists")]
        List<Person> GetAllArtists();


        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Xml,
            RequestFormat = WebMessageFormat.Xml,
            UriTemplate = "artists")]
        bool PostArtist(Person PersonObject);

        [OperationContract]
        [WebInvoke(Method = "DELETE",
            ResponseFormat = WebMessageFormat.Xml,
            RequestFormat = WebMessageFormat.Xml,
            UriTemplate = "artists/{id}")]
        bool DeleteArtist(string id);

        [OperationContract]
        [WebInvoke(Method = "PUT",
            ResponseFormat = WebMessageFormat.Xml,
            RequestFormat = WebMessageFormat.Xml,
            UriTemplate = "artists/{id}")]
        bool PutArtist(Person PersonObject, string id);

    }

The operations on the group of artists as a whole are completed using POST and GET against the service root URI: /JazzService.svc/artists. Reading, updating and deleting of individual artists are accomplished through their own, individual URI: /JazzService.svc/artists/{artistID}. Thus, a URI is exposed for every piece of data (the group and each individual) on which the client is allowed to operate.

Additionally, the URI has no indication of the method being used. It only points to the resource (data). All method information is contained in the HTTP method: POST, GET, PUT, DELETE.

By restricting the method information to the HTTP method, putting the scope information in the URI and exposing a URI for each resource, this new service meets Richardson’s and Ruby’s basic criteria for a RESTful, resource-oriented web sevices. But we aren’t done with the service if we want it to be truly RESTful. In my next REST post, we’ll discuss the REST constraint of Hypermedia as the Engine of Application State (HATEOAS) and how we can add it to our Jazz Artist web service.

You can see the current working example of this service on my development site.


1. Richardson, Leonard and Ruby, Sam. RESTful Web Services. Sebastopol: O’Reilly Media, Inc., 2008. Ebook

Consuming a RESTful web service with jQuery and Ajax

In my last post, we created a REST WCF web service using Visual Studio 2010. In this article, we’ll write a client side web applicaiton that uses jQuery and Ajax to consume a REST web service.

First, create an HTML page that includes a reference to a jQuery library, a <div> tag where we’ll display the service output, a button that will fire the Ajax request to the web service and one that will clear the output <div>.


<html>
<head>
<title>Consume a REST Web Service</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"/>
</head>
<body>
<p><div id="myOutput">Output Goes Here</div><p>
<p><input id="myButton" value="Get Artist" type="submit" /></p>
<p><input id="myClearButton" value="Clear Artist" type="submit" /></p>


Next, add the jQuery to run when the Get Artist button is clicked.

<script type="text/javascript">
 $("#myButton").click(function() {
        var artistURL = "http://development.dlwelch.com/examples/restservice/JazzArtists.svc/json/Shirley";
        var returnData = "";
        $.ajax({
            type: "GET",
            dataType: "json",
            async: true,
            url: artistURL,
            error: function(request, status, error) { alert(request.responseText) },
            success: function(data) {
                $("div#myOutput").html(" ");
                returnData = "<table style='font-size:8pt;'><tr><th>Artist</th><th>Grammys</th></tr>";
                for (prop in data) {
                    if (!data.hasOwnProperty(prop)) { continue; }
                    if (data[prop] != null) {
                        for (var i = 0; i < data[prop].length; i++) {
                            returnData += "<tr><td>" + data[prop][i]["FirstName"] 
                                       + " " + data[prop][i]["LastName"] + "</td><td align='right'>" 
                                       + data[prop][i]["Grammy"] + "</td></tr>";
                        }
                    }
                }
                returnData = returnData + "</table>";
                $("div#myOutput").html(returnData);
            }
        });
        return (false);
    });
</script>

...

Code line 3 defines the URI of the resource, in our case, the artist Shirley. Line 6 indicates we are sending an HTTP GET request to the resource and line 7 says we’ll evaluate the response as JSON and send a JavaScript object back to our success function on line 11. Since a JavaScript object was returned, line 14 starts the loop to find the property holding the response data. Line 15 test the current property to see if it’s a built in property of a JavaScript object. If so, skip it. Once we reach the property with our data, we loop through all the artist objects and create our HTML string for the output <div>.

Finally, add the jQuery to clear the output and finish your HTML.

<script type="text/javascript">
 $("#myClearButton").click(function() {
        $("div#myOutput").html("Output Goes Here");
        return (false);
    });

</script>


</body>
</html>


Your page should look like this. Click on the Get Artist button to see it work!



You can see a working example and grab the code for Ajax calls of all four HTTP verbs on my development site in the WCF RESTful Web Service example.

JavaScript, jQuery and Ajax for reporting on SharePoint lists

In this post, I will show you how to query two SharePoint lists using jQuery and Ajax. We will then combine the results into a summary report. I originally created this example for SP 2007 with the requirement it be completed using only client side capabilities. In addition, the customer wanted a graphical representation of the data and a drill down to details for each record, without the use of custom web parts.

The first list contains master project data.

The second list is a project status log which is populated by a workflow on the Projects List. Each time the project status is changed, an item is created in this project status list.

Now we’ll create our report using client-side scripting. I used SharePoint Designer 2007 and created a new web page at the root of the site. But you can also use a Content Editor Web Part to hold your script.

First, add a <div> to your page that will display a loading image and notification while your Ajax runs. We’ll hide this <div> once it’s done.

<div id="wait">
<p align="center"><img src="GEARS_AN.GIF" alt="Please wait..." />
<br/>Generating report..
</p>
</div>

Then add another <div> where you will display your results. I wrapped mine in a <table> so I can easily add rows with more information later.

<table class="ms-vb" cellpadding="1" border="0">
<tr><td>
<div id="listLinks"> </div>
</td></tr> 
</table> 

Now for the script. Define two JavaScript objects. One for the project list items and one for the statuses. Add an .ajaxStop function which will run when all Ajax calls complete. The .unbind function prevents it from running again if a subsequent Ajax call is made after the document loads. Finally, define what should happen when the document is ready.

<script type="text/javascript">

 var myProjArray = new Object();
 var myStatusArray = new Object();

 $(document).ajaxStop(function() {
  $(this).unbind("ajaxStop");
  createprojectstable();
 });

 $(document).ready(function() {
  getProjects();
 });

When the document is ready getProjects() runs. Since CAML joins are only supported in SharePoint 2010+, I have to make an extra Ajax call for each project to get the status items. A single call could have been made to return all status items rather than making a call for each project returned by the first. However, that list may have been much larger than needed if we were to restrict the projects returned in the first CAML query by using a WHERE clause. Your particular circumstance will dictate which approach to take.

//****************************************************************************************
//get projects from the Projects List
function getProjects(){

 var thisurl = window.location.href;
 var i = thisurl.lastIndexOf("/");
 var asmxlocation = thisurl.substr(0,i)
 asmxlocation = asmxlocation + "/_vti_bin/lists.asmx";


 var soapEnv = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
     <soapenv:Body> \
     <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
      <listName>Projects List</listName> \
      <viewFields> <ViewFields> \
        <FieldRef Name='ID' /><FieldRef Name='Title' /> <FieldRef Name='ProjStatus' /> <FieldRef Name='Created' /> <FieldRef Name='Team' /> \
      </ViewFields> </viewFields> \
      <rowLimit>2000</rowLimit> \
      <query> <Query> \
        <OrderBy><FieldRef Name='Team' Ascending='TRUE' /><FieldRef Name='Title' Ascending='TRUE' /></OrderBy> \
      </Query> </query> \
     </GetListItems> \
     </soapenv:Body> \
     </soapenv:Envelope>";

$.ajax({
url: asmxlocation,
type: "POST",
dataType: "xml",
data: soapEnv,
async: true,
complete: processResult,
contentType: "text/xml; charset=\"utf-8\""
});

}

//**************************************************************************************** 
//process results from projects query
function processResult(xData, status) {

$(xData.responseXML).find("z\\:row").each(function() { 

myProjArray[$(this).attr("ows_ID")] = [$(this).attr("ows_Title"),$(this).attr("ows_ProjStatus"),$(this).attr("ows_Created"),$(this).attr("ows_Team") ]; 

//CAML Joins are only available in SP 2010+ so we got to loop
getProjectStatus($(this).attr("ows_ID")); 

});
} 

//****************************************************************************************
//get status records for a specific project
function getProjectStatus(ProjID){

var thisurl = window.location.href;
var i = thisurl.lastIndexOf("/");
var asmxlocation = thisurl.substr(0,i)
asmxlocation = asmxlocation + "/_vti_bin/lists.asmx";


var soapEnvZ = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
    <soapenv:Body> \
    <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
      <listName>Project Status Log</listName> \
      <viewFields> <ViewFields> \
         <FieldRef Name='ID' /> <FieldRef Name='ProjectID' /> <FieldRef Name='Status' /> <FieldRef Name='Created' /> \
      </ViewFields> </viewFields> \
      <rowLimit>1000</rowLimit> \
      <query> <Query> \
        <Where> <Eq> <FieldRef Name='ProjectID' /> <Value Type='Counter'>" + ProjID + "</Value> </Eq> </Where> \
        <OrderBy><FieldRef Name='Created' Ascending='TRUE' /></OrderBy> \
      </Query> </query> \
    </GetListItems> \
    </soapenv:Body> \
    </soapenv:Envelope>"; 

$.ajax({
url: asmxlocation,
type: "POST",
dataType: "xml",
async: true,
data: soapEnvZ,
complete: processResultZ,
contentType: "text/xml; charset=\"utf-8\""
});
}

//****************************************************************************************
//process results from the status query
function processResultZ(xData, status) {
var statusarray = new Array();
var arraycounter = 0
var projID;

$(xData.responseXML).find("z\\:row").each(function() { 
   statusarray[arraycounter++] = [$(this).attr("ows_Status"),$(this).attr("ows_Created")];
   projID = parseInt($(this).attr("ows_ProjectID"));
   myStatusArray[projID] = statusarray;
}); 

}

Now that we have the projects and statuses objects with a common property, the ID of the project, we can display the data any way we wish. createprojectstable() runs when the Ajax calls have completed and creates the HTML and JavaScript for the reports. I created a horizontal bar representing the length of time in each status for each project. There is also a drop down text area of the status details for each project. This is just another table row that is hidden and made visible by clicking the table row containing the graph. Click on the different elements below to see a live demo.

 

Here’s the interesting parts of creating the report – looping through the properties of the project and statuses objects to build the output HTML. (Note that, even though they are named “array”, they are actually objects.) And finally, we’ll hide the loading image and notification <div>.

function createprojectstable(){

var outHtml = "..."

//create report headings

for (prop in myProjArray) { 
  if (!myProjArray.hasOwnProperty(prop)) { 
    continue; //The current property is not a direct property of p, so goto the next one. i.e. it is not a poperty we created but a built-in JavaScript     property 
  } 

  //create HTML for each project

  if (myStatusArray[prop] !== undefined){
    //and now create the status details for the project
  }
  outHtml += "..."
  $("#listLinks").append(outHtml); 
  $("#wait").hide(); 

  //create report footers and initiate any other report options
}

You can download the source of a working example. This one reads XML files instead of SharePoint lists but is essentially the same. I’ve only tested the code in IE 8 and Firefox 5 but it would probably be quick work to make it cross-browser compatible.