Introducing Windows Communications Foundation

At the core of the service-based AJAX application architecture is the data services layer. This layer exposes the back-end system through Web services and XML endpoints. To build data services for AJAX with ASP.NET 2.0, I would use a combination of SOAP-based ASMX Web services and HTTP handlers for simple XML data streams. With the 3.5 release of the .NET Framework, you can use Windows Communication Foundation, or WCF, to provide data services that are built from the ground up with service orientation in mind. Service orientation describes the architectural commitment to provide message-based applications that are loosely coupled, well defined, and abstracted from implementation details. A service-based AJAX application is built to reflect many of the principles of service-orientation.

WCF services in the .NET 3.5 Framework were built with AJAX applications in mind and include a flexible communications architecture that targets the ASP.NET AJAX library. WCF supports simple XML endpoints (also known as POX, or Plain Old XML), SOAP messages, and data serialization with JSON, the JavaScript Object Notation syntax. Because WCF is integrated with the ASP.NET AJAX Extensions through behaviors, ASP.NET AJAX can generate JavaScript proxies for WCF Web services that make consuming the services from AJAX applications easy and maintainable.

More Information

More Information

For in-depth coverage of WCF as a service-oriented architecture platform, I recommend the book Pro WCF: Practical Microsoft SOA Implementation (APress, 2007).

WCF is a technology first introduced with the .NET 3.0 Framework. It is simpler to implement than classic ASP.NET ASMX Web services and includes a more flexible programming model. I’ll discuss WCF in detail in Chapter 2, and Chapter 3, but for now let’s look at some simple examples to get started. You’ll see that programming WCF is straightforward and perhaps the easiest way yet for Microsoft developers to expose back-end data as XML.

Tip

Tip

While this book uses WCF to implement the services layer, you can also use the same techniques to program against ASP.NET 2.0 Web Services by applying the ScriptService attribute to each Web service. For POX endpoints with ASP.NET 2.0, you can use HTTP handlers implemented with the IHttpHandler interface.

To get started, first create a new WCF Service Library, or simply a class library with references to System.ServiceModel and System.ServiceModel.Web. The service library is basically a class library, but it also lets you test your WCF endpoints directly, without a Web application. I generally prefer to create a class library containing WCF service classes and interfaces and reference that class library from the ASP.NET Web application project.

Because services are defined outside ASP.NET in service libraries, you can host these services in multiple ASP.NET Web applications or WCF hosting environments. To add a service library to an ASP.NET Web application, simply add a reference to the WCF class library in the Web project. In the next section, we’ll look at defining the service endpoints and registering them with ASP.NET through the web.config file.

XML Endpoints with WCF

The simplest Web service endpoint is known as Plain Old XML (POX), which is a Web service without the SOAP message wrapper. While SOAP-based Web services offer rich semantics for remote procedure calls and are extensible through the WS-* specifications, SOAP is not always the best solution for data retrieval for Web applications. In fact, Web services called from JavaScript proxies using ASP.NET AJAX do not use SOAP at all. Instead they use a simple POST implementation. POX endpoints offer several architectural advantages and can make use of Web caching technologies implemented by proxies and modern Web browsers. In Chapter 3, you’ll see detailed examples of the REST (Representational State Transfer) architectural pattern that builds on POX endpoints, but first let’s look at using basic WCF endpoints to build POX services for AJAX applications.

To build a simple XML endpoint with WCF, create a new class in the WCF Service Library project. In this example, I created a class named SimpleXmlService with a single HelloWorld method that returns an XML element. WCF services are defined through attributes, much like the use of the WebService and WebMethod attributes to define Web services in classic ASP.NET. In WCF, you use the attribute ServiceContract to define a WCF service class and the attribute OperationContract to define any WCF service method. It is important to note that you must also include the AspNetCompatibilityRequirements attribute to allow the WCF service to run in ASP.NET.

In the service code shown in Example 1-7, the SimpleXmlService class defines a method that returns an XmlElement and includes the ServiceContract and AspNetCompatibilityRequirements attributes on the class. The HelloWorld method has both an OperationContract attribute and a WebGet attribute. The WebGet attribute allows WCF to expose the method through an HTTP GET endpoint, meaning that you can simply access the XML through a URL.

Example 1-7. A simple XML WCF service (Web/SimpleXmlService.cs).

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Xml;

namespace WcfFundamentals
{
    [ServiceContract(Namespace="SimpleXmlService")]
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class SimpleXmlService
    {
        [WebGet]
        [OperationContract]
        public XmlElement HelloWorld()
        {
            var doc = new XmlDocument
            {
                InnerXml = "<message>Hello XML World!</message>"
            };
            return doc.DocumentElement;
        }
    }
}

Tip

Tip

Throughout this book I’ll use C# 3.0 syntax, compiled to run against the .NET 3.5 Framework. If this syntax is new to you, I recommend picking up Joe Mayo’s book C# 3.0 Unleashed: With the .NET Framework 3.5 (Sams Publishing, 2008).

Because I defined SimpleXmlService as an XML endpoint that is exposed through a URL, I can use the general purpose Sys.Net.WebRequest object to get the XML. I don’t need to use a JavaScript Web service proxy to access the data. The Hello World Web request page in Example 1-8 demonstrates a simple Web request to the XML endpoint and renders the response message on the page. In a real application, this request might be executed many times during the page’s life cycle or in response to user actions. Because the application is service-based (however simple it may be), you can reuse the service in multiple applications.

Example 1-8. The Hello World Web request page demonstrates a simple AJAX network request (Web/SimpleXmlWebRequest.aspx).

<%@ Page Language="C#" AutoEventWireup="true" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>ASP.NET AJAX: Fundamentals: Simple XML Web Request</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="AspxScriptManager" runat="server"/>
    <div id="MainContent">
        Loading...
    </div>
    </form>

    <script language="javascript" type="text/javascript">
        function OnAjaxLoad(){
            var req = new Sys.Net.WebRequest();
            req.set_url('SimpleXmlService.svc/helloworld'),
            req.add_completed(ajaxDataCallback);
            req.invoke();
        }

        function ajaxDataCallback(response){
            var content = $get('MainContent'),
            var xml = response.get_xml();
            if (xml == null)
                Sys.Debug.fail('Could not load the message!'),

            var messageNodes = xml.getElementsByTagName('message'),
            if (messageNodes.length == 1)
                if (messageNodes[0].textContent) // ff
                    content.innerHTML = messageNodes[0].textContent;
                else //ie
                    content.innerHTML = messageNodes[0].text;
        }

        Sys.Application.add_load(OnAjaxLoad);
    </script>
</body>
</html>

Now that you’ve seen simple XML endpoints, it’s time to look at updating data in an AJAX application. Just as you use services for data retrieval, you can use services to update data. WCF makes exposing these methods to the AJAX client through JavaScript proxy classes quite easy. With WCF, JavaScript proxy classes are generated by the ASP.NET AJAX runtime through behaviors enabled in web.config.

Tip

Tip

In the same way that you can build Web service proxies for C# class libraries in Visual Studio by adding a Web reference, you can use JavaScript proxy classes for JavaScript class libraries. The proxies allow you to call a native JavaScript method rather than worrying about the Web service message semantics and network operations. JavaScript proxy classes are generated dynamically by the ASP.NET AJAX framework by adding a service reference to the ScriptManager control.

Updating Data with WCF Services

While SOAP or POST based Web services aren’t always the ideal mechanism for loading data, they are an ideal mechanism for method calls, especially complex data input or modification. And with WCF, you don’t really need to make this distinction—the same WCF method can be exposed as a simple XML endpoint (POX) or a SOAP endpoint. The code in the service doesn’t need to change. You also don’t need to make any commitments to AJAX or any other client technology—your services layer will be completely separate from the AJAX interface. In fact, you can choose to expose your WCF application over alternate transports such as MSMQ, TCP/IP channels, or even SMTP.

Note

Note

A wiki is a notepad-like application for collaboration on the Web, designed for speed and ease of use. Throughout the book, we’ll use wikis as examples of AJAX applications, and we’ll be building a knowledge base application as a case study using wiki techniques. For more information on wikis, see http://en.wikipedia.org/wiki/Wiki.

For the first example, I’ll create a simple Web service that remembers a message in application state. I’ll start off by defining a data class named WikiData. This data class is the starting point for the WCF service—it defines the message returned by the service. To define the data structure, you use the DataContract and DataMember attributes. The WikiData class has a DataContract attribute to define the namespace of the elements, and DataMember attributes to define the XML-serialized elements. The WikiData class is defined in Example 1-9. By defining this contract, you can program any client application against this data format.

Example 1-9. The WikiData data contract (WcfFundamentals/WikiData.cs).

using System.Runtime.Serialization;

namespace WcfFundamentals
{
    [DataContract(Name = "WikiData", Namespace = "ServiceOrientedAjax.Examples")]
    public class WikiData
    {
        [DataMember]        public string Title { get; set; }

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

The DataContract defined in Example 1-9 will output the following XML format:

<WikiData xmlns="ServiceOrientedAjax.Examples"
        xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Body>Hello WCF World!</Body>
    <Title>example</Title>
</WikiData>

After defining the data contract, the next task is to implement the service. You can create the service using a Visual Studio template or by defining a class marked with the ServiceContract attribute, which identifies a class as a WCF service implementation. Each method that it exposes as a Web service endpoint must be marked with the OperationContract attribute. The OperationContract attribute is similar to the WebMethod attribute used with ASP.NET Web Services and defines a method that is exposed through WCF endpoints.

Because I defined the data class WikiData with the DataContract attribute, I can use WikiData as the return type of the Get request and also as the input parameter on the Set operation. Example 1-10 defines a simple WCF service that uses the WikiData data contract defined in Example 1-9.

Example 1-10. A simple wiki WCF class using the WikiData data contract (WcfFundamentals/SimpleWikiService.cs).

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web;
using System.Runtime.Serialization;

namespace WcfFundamentals
{
    [ServiceContract(Namespace = "ServiceOrientedAjax.Examples")]
    [AspNetCompatibilityRequirements(RequirementsMode =
         AspNetCompatibilityRequirementsMode.Allowed)]
    public class SimpleWikiService
    {
        [OperationContract]
        public void SetWiki(WikiData wiki)
        {
            HttpContext.Current.Application[wiki.Title] = wiki.Body;
        }

        [OperationContract][WebGet]
        public WikiData GetWiki(string title)
        {
            WikiData wiki = new WikiData{
                Title = title,
                Body = (string)HttpContext.Current.Application[title]
                       ?? "Hello WCF World!"
                };
            return wiki;
        }
    }
}

After defining the WCF service, you need to define the endpoint in the ASP.NET application through a service (SVC) file and web.config. The service file is a simple text file that is used by ASP.NET to activate the WCF service endpoint. The service file should contain the following reference to the SimpleWikiService WCF endpoint:

<%@ ServiceHost Service="WcfFundamentals.SimpleWikiService" %>

After ensuring that the service endpoint is defined in an SVC file, you must also define its endpoint and behaviors in web.config. Behaviors can apply to multiple endpoints and can change how the client accesses the WCF endpoint. In this example, I defined both a POX endpoint and a JSON-enabled endpoint with enableWebScript. These additional behaviors are enabled through the behaviorConfiguration element.

To enable ASP.NET AJAX to build a JavaScript proxy class for the service, you can specify the enableWebScript behavior, which can be mapped to multiple WCF endpoints. The following example defines the JsonBehavior behavior configuration (the name "JsonBehavior" is arbitrary), which includes the enableWebScript behavior:

<behaviors>
  <endpointBehaviors>
    <behavior name="JsonBehavior">
        <enableWebScript />
    </behavior>
  </endpointBehaviors>
</behaviors>

The enableWebScript behavior also converts the default response from XML format to JSON format, using JavaScript object notation to define the data. This format can be easier to work with when manually processing the data and not using an XSLT transformation. Because WCF abstracts endpoint behavior from implementation, you can define both an XML endpoint and a JSON endpoint in web.config without any changes to the service. The endpoint is mapped to a URL and defines how the client accesses the service. It’s important to realize that this mapping is performed through configuration and not during service development, as you’ll see in the following example.

To define an additional endpoint that provides JSON data, you can use web.config to map an endpoint to a behavior configuration. For example, I mapped an additional endpoint to SimpleWikiService.svc/json, which will be a JSON-enabled endpoint with the same implementation as the SimpleWikiService.svc endpoint. To define the endpoint, create a service element with a child endpoint element. The endpoint element defines the address, behavior configuration, binding, and contract for the service. The address of the endpoint is relative to the .svc file that activates the WCF service, and behaviorConfiguration defines additional behaviors for the endpoint. The following example defines the service endpoints for SimpleWikiService, with an additional endpoint mapped to "/json" that uses the JsonBehavior configuration:

<services>
    <service name="SimpleWikiService">
        <endpoint address=""
             binding="webHttpBinding" contract="SimpleWikiService" />

        <endpoint address="json" behaviorConfiguration="JsonBehavior"
            binding="webHttpBinding" contract="SimpleWikiService" />
  </service>
</services>

The data contract specified in Example 1-9 will output the following JSON data stream when accessed through an endpoint with the enableClientScript behavior:

{"d":{"__type":"WikiData:ServiceOrientedAjax.Examples",
    "Body":"Hello WCF World!","Title":"example"}}

This JSON-formatted data stream contains the same content as the XML output defined by the data contract. Because JSON streams are easier to work with in script if you’re not applying an XSLT transformation, Microsoft chose this as the default behavior for script-enabled Web services.

Because we have the enableWebScript behavior defined in web.config for the /json endpoint, the ASP.NET AJAX runtime will generate a JavaScript proxy for the service. This proxy is all you need to call the WCF service and handle its response. To examine the JavaScript proxy manually, use the WCF endpoint and add the "/jsdebug" switch to the end of the URL, such as http://localhost/ajaxfundamentals/simplewikiservice.svc/json/jsdebug. The proxy will contain the correct JavaScript syntax details for calling the Web service through the ASP.NET AJAX JavaScript framework, including serialization objects for calling and retrieving the data. For now though, all you need to know is that the proxy generates static (not instance) JavaScript methods for each WCF operation. The public methods call instance methods of the proxy that you won’t call directly. For each Web service operation, three parameters are added to the method parameters: onSuccess, onFailed, and userContext. Because all network calls are made asynchronously, you must pass in callback handlers for the response. The userContext object is passed unchanged to the callback and generally contains a pointer to the AJAX component that called the method, although you can pass any object as the user context.

Following is the main public proxy methods that are generated for our WCF endpoint, with the methods GetWiki and SetWiki. Although the actual proxy contains more code, the JavaScript functions that correspond to the public service methods are generally the only methods you will need to call.

GetWiki:function(title,succeededCallback, failedCallback, userContext) {
   return this._invoke(this._get_path(),'GetWiki',true,{title:title},
      succeededCallback,failedCallback,userContext); }}

SetWiki:function(wiki,succeededCallback, failedCallback, userContext) {
   return this._invoke(this._get_path(), 'SetWiki',false,{wiki:wiki},
      succeededCallback,failedCallback,userContext); }

To use this code in our AJAX application, you need to reference the JavaScript proxy classes generated by ASP.NET AJAX. To do this, you use the ScriptManager control, defining a reference to SimpleWikiService.svc in the Services node. To add a ServiceReference, add a ServiceReference node with the Path parameter to your WCF endpoint, as in the following example:

<asp:ScriptManager ID="AspxScriptManager" runat="server" >
    <Services>
       <asp:ServiceReference Path=" SimpleWikiService.svc/json" />
    </Services>
</asp:ScriptManager>

The full code for our simple WCF-based Web application is shown in Example 1-11. Building on these simple principles, later in the book you will develop components that encapsulate client-side logic and enable deployment across multiple contexts throughout multiple applications.

Example 1-11. Using WCF operations for AJAX back-end services (Web/SimpleWikiPage.aspx).

<%@ Page Language="C#" AutoEventWireup="true"  %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>ASP.NET AJAX: Fundamentals: Simple Wiki with WCF</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="AspxScriptManager" runat="server" >
        <Services>
            <asp:ServiceReference Path="SimpleWikiService.svc/json" />
        </Services>
    </asp:ScriptManager>
    <div id="MainContent" onclick="editMessage">
        Loading...
    </div>
    <br />
    <span   style="border:solid 1px silver;"
            id="editButton"
            onclick="editMessage();" >
        Edit
    </span>

    <div id="EditorRegion" style="display:none;">
        <textarea id="TheEditor" rows="10" cols="80" ></textarea>
        <br />
        <span style="border:solid 1px silver;" onclick="save();" >
            Save
        </span>
    </div>

    </form>

    <script language="javascript" type="text/javascript">
        var wikiName = 'default';

        function OnAjaxLoad(){
            var userContext = new Object();
            ServiceOrientedAjax.Examples.SimpleWikiService.GetWiki(
                wikiName, getMessageSuccess, onMessageFailure, userContext);
        }

        function editMessage(){
            $get('EditorRegion').style.display='';
            $get('editButton').style.display='none';
            $get('MainContent').style.display='none';
            $get('TheEditor').value = $get('MainContent').innerHTML;
            $get('TheEditor').enabled= true;
        }

        function getMessageSuccess(wikiData, userContext){
            var EditorRegion = $get('EditorRegion'),
            EditorRegion.style.display='none';
            var content = $get('MainContent'),
            content.innerHTML = wikiData.Body;
            content.style.display='';
        }

        function save(){
            var msg = $get('TheEditor').value;
            var userContext = new Object();
            userContext.msg = msg;
            userContext.title = wikiName;
            var wiki = new Object();
            wiki.Title=wikiName;
            wiki.Body = msg;
            ServiceOrientedAjax.Examples.SimpleWikiService.SetWiki(
                wiki, onSaveSuccess, onMessageFailure, wiki);
            $get('TheEditor').enabled= false;
        }

        function onSaveSuccess(response, wiki){
            getMessageSuccess(wiki,null);
        }

        function onMessageFailure(ex, userContext){
            var content = $get('MainContent'),
            content.innerHTML = ex;
        }

        Sys.Application.add_load(OnAjaxLoad);
    </script>
</body>
</html>

Example 1-11 defines a simple wikilike application. To initialize the page, we use the OnAjaxLoad event handler method to load the data with the GetWiki JavaScript proxy method. When the user clicks the Edit button, we hide the display and show a data input form, allowing the user to edit the contents of the wiki item. When the user is finished editing, we save the content using the save method, which calls the SetWiki method. Because we have a JavaScript proxy to our WCF methods, we don’t have to worry about the semantics of the call; we simply call our JavaScript methods. Because the network operations of the Web service proxy are asynchronous, we pass in the onSaveSuccess method as the callback handler.

With these simple examples, you’ve seen the fundamentals of AJAX applications using a service-based architecture and Microsoft’s ASP.NET AJAX framework, utilizing WCF as the services layer and the Microsoft AJAX Library on the client. With these building blocks you can build very powerful and robust AJAX applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset