Assignment

karthikrao0207
chapter3book.pdf

Creating Consumable Web Services for Mobile Devices

WHAT’S IN THIS CHAPTER?

! Understanding web services

! Using web service languages (formats)

! Creating an example service

! Debugging web services

Many of today’s mobile applications are personalized, and are not useful if they can only access the data on the phone. For a user to get, for example, sports scores, retrieve stock quotes, or perform accounting work, the mobile device needs to communicate with one or more servers. The best way to achieve this communication is through web services.

This chapter covers what a web service is, the technologies involved in web services, and how to create web services on the Windows platform and the Linux platform. Four different walkthroughs show you how to create web services with four different technologies.

WHAT IS A WEB SERVICE? A web service enables two electronic devices to communicate over the Internet. The World Wide Web Consortium (W3C) defi nes web service as “a software system designed to support interoperable machine-to-machine interaction over a network.” In practice this means a server communicating over port 80 or port 443 in plain text to the client.

Other methods of communication are remote procedure calls (RPC), the distributed component object model (DCOM), and the common object request broker architecture (CORBA). These methods of communication don’t work well through the Internet due to fi rewalls and the data

3

c03.indd 37c03.indd 37 28/07/12 5:49 PM28/07/12 5:49 PM

38 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

formats they use. Typically their data formats are specifi c to whatever tool created the service, and it becomes a signifi cant challenge to have a Java application read data from a .NET or C++ application. They generally also use a specifi c port, which requires IT departments or, even worse, home users, to troubleshoot and confi gure their fi rewalls to allow the application to communicate. Finally those technologies don’t work well through the Internet because they aren’t designed to work with the Hypertext Transfer Protocol.

WHAT IS A PORT?

A port is similar to a TV channel. News comes in on the news channel, sports on ESPN, and so on. Instead of watching the channels, computer applications are listening on port numbers. The information coming to the computer on that port number is routed to the application listening on that port number. For example, when your computer requests a web page from a web server, it issues the request through port 80. That traffi c is delivered by the server’s operating system to a HyperText Transfer Protocol (HTTP) server application such as Microsoft’s Internet Information Services (IIS) or the Apache Web Server. Connecting with a fi le transfer protocol (FTP) client to the same server, the FTP software uses port 21. Both FTP and HTTP traffi c are going to the same computer with the same address, so having different ports enables the server to route the traffi c to the correct application.

Examples of Web Services Because you are reading this book, I’m assuming you are a developer or have some type of development background, so I’ll use the StackOverfl ow web service as an example. You can view my StackOverfl ow profi le by using a nice user interface StackOverfl ow has created to access their web service by going to http://data.stackexchange.com/stackoverflow/query/66263/ find-david-silva-smith in a web browser. That URL is a query which shows the data from my StackOverfl ow profi le. To view my profi le data in its raw form to compare it to the pretty formatted data just shown, enter this URL in a browser: http://data.stackexchange.com/stackoverflow/ atom/Users(46076).

Think how easily an application can be written using that data. This is the power of web services. By making your data easily consumable through web services, others can use the data you have created in ways you never imagined.

Not convinced yet? What if you wanted to display the weather for Lansing, Michigan, on your web page? How hard would that be to program? For starters, you would have to purchase equipment to measure the temperature, wind speed, and humidity, which could be expensive. Then you would have to program that equipment to report the information to a web server, which would then display that information on your web page. Wow, this is sounding diffi cult, and there are many issues that haven’t been addressed yet, such as reliability. Instead of doing all that work, leveraging a

c03.indd 38c03.indd 38 28/07/12 5:49 PM28/07/12 5:49 PM

What Is a Web Service? " 39

web service will be much faster. Simply type this URL into a web browser: http://www.google .com/ig/api?weather=Lansing,MI. No equipment required, no risk of schedule overruns, and if requirements change and the software needs to display the weather for Lake Odessa instead of Lansing, you just replace the Lansing,MI on the end of the URL with Lake%20Odessa,MI.

WHAT IS THAT UGLY %20?

Not all characters are valid in uniform resource locators (URLs). A space is one such character — it is represented as %20. The percent sign indicates that the follow- ing two hexadecimal characters represent a single character — 20 in hexadecimal is 32 in decimal, which is the ASCII code for space. If that isn’t confusing enough, different characters are valid in different parts of a URL. To encode a URL, use the JavaScript encodeURI() method or the equivalent function in your programming language. For parts of a URL, use the JavaScript encodeURIComponent() method or the equivalent function in your programming language. This JavaScript code shows an example of when this difference is important:

<script type=”text/javascript”> var url = ‘http://www.gravityworksdesign.com/ large images.aspx?folder=2012/April’; document.write(encodeURI(url)); document.write(‘<br />’); document.write(encodeURIComponent(url)); var urlCorrect = ‘http://www.gravityworksdesign.com/ large images.aspx?folder=’ var queryCorrect = ‘2012/April’; document.write(‘<br />’); document.write(encodeURI(urlCorrect) + encodeURIComponent(queryCorrect)); </script>

It outputs:

http://www.gravityworksdesign.com/large%20images. aspx?folder=2012/April http%3A%2F%2Fwww.gravityworksdesign.com%2Flarge%20images.aspx %3Ffolder%3D2012%2FApril http://www.gravityworksdesign.com/large%20images.aspx? folder=2012%2FApril

The fi rst two URLs are invalid because the URL wasn’t encoded correctly. The third URL is correctly encoded.

Advantages of Web Services The primary advantages web services provide are ease of access and ease of consumption. Web services advantages stem from simplicity. Usage of web services for data exchange has exploded due to these advantages.

c03.indd 39c03.indd 39 28/07/12 5:49 PM28/07/12 5:49 PM

40 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

Web services are easy to access because they use the same World Wide Web technologies such as web browsers and web servers that power the Internet. These technologies have proven to be robust and work great for web services just as they work great for delivering web pages. They have no fi rewall issues with special ports like other communication technologies, and all modern programming languages provide a way to get web pages and, therefore, to consume web services.

The second advantage of web services over other technologies is the consumability, which is the ability to understand what the server is communicating. Web services use plain text for this. Other technologies like RPC, DCOM, and CORBA typically use the in-memory representation of their objects for transmission or use a custom data exchange format. These complexities make it expensive for languages to interoperate with the information. The memory representations don’t have friendly text like <zipcode>48906</zipcode>, which most people can guess contains ZIP code information; the server might send something like 1011111100001010, which could represent many pieces of information. This discussion leads us into the next section, which discusses web service languages.

WEB SERVICES LANGUAGES !FORMATS" For communication to occur between two people they need to speak the same language. Computer systems work the same way — they also need to use the same language. Most computer languages that are widely known, such as C++, enable humans to talk to computers. But those computer languages are hard for both computers and humans to understand because computers only understand zeros and ones, and represent all data as zeros and ones. For example, the number 5 is represented as 00000101 in a computer. A lowercase h is represented as 01101000, and 01001000 represents an uppercase H. Binary representations are the most effi cient way for two computer systems to exchange data.

One of the reasons web services have been so successful is because of their self-describing nature. Instead of giving a number like 5 and hoping the user of the web service knows that 5 is a weight, an age, or dollars, the 5 is described in a service like this: <length measurement=”inches”>5 </length>. This states clearly the measurement is for length and is 5 inches.

Format choice is an important decision — it impacts the ease of accessing the web service and the performance of your application. When designing a web service, consider how the service will be accessed. For example, mobile devices have less processing power than their desktop counterparts, and the different platforms (BlackBerry, Windows Phone, Android, and iOS) have different programming APIs available for accessing and consuming the data. The two self-describing formats that have taken off for web services are XML and JSON. I recommend sticking with one of these two formats to maximize the ease of consuming the services and maximize developer productivity.

eXtensible Markup Language (XML) XML was designed as a way to describe documents, but it took off as a data interchange format after it was introduced. XML was envisioned to be a simple human-readable language; for example, a person object can be represented like this in XML:

<person> <firstname>David</firstname> <lastname>Smith</lastname> </person>

c03.indd 40c03.indd 40 28/07/12 5:49 PM28/07/12 5:49 PM

Web Services Languages (Formats) " 41

And the same person can also be represented like this:

<person firstname=”David” lastname=”Smith” />

Both XML fragments are easy for a person to understand, but different representations make it harder for programmers to write correct software. Having a single agreed-upon representation of the data will speed up your development effort.

XML enables you to defi ne the language systems used to communicate by creating an XML Schema Document (XSD). This enables software to verify an XML document conforms to a predefi ned contract. For example, the XSD can specify that the cost of a movie must be a number. XSD also provides the benefi t of enabling tools to generate code based on the XSD. Programmers can increase productivity by feeding their programming tool an XSD fi le and getting back code they can immediately use to interact with the data. Without the XSD fi le programmers have to write code to understand the XML.

One of the reasons for choosing XML is the maturity of the platform. It has been around since February 1998. It has many tools around it — XPath, XQuery, XSLT, and XSD. Since it is a mature language, many systems work well with XML. These advantages make XML a good choice for data interchange and it may even be required for some projects to work with existing systems.

eXtensible Stylesheet Language Transformations (XSLT) XSLT is used to transform a document into another representation. Initially it was envisioned as primarily changing XML data documents into representations for human consumption, such as XHTML. Another common use is applying an XSLT transformation to one application’s XML output to be used by another application that doesn’t understand the original representation.

The following example shows how XSLT can transform an XML data fragment for display on a web page.

This fragment: <person><age>30</age></person> would better be displayed on a web page like this: <span>Age:30</span>.

The following XSLT will loop through each element in the XML with the name of person. Within each person node, the XSLT will then output the span tag with the value of the age element included within the span tag.

<xsl:template match=”/”> <xsl:for-each select=”person”> <span>Age:<xsl:value-of select=”age”/></span> </xsl:for-each> </xsl:template>

XQuery XQuery is used to retrieve a subset of data from a full XML document, like a SQL query is used to retrieve a subset of data from a database.

This example shows how to get the total amount paid for this sample order:

c03.indd 41c03.indd 41 28/07/12 5:49 PM28/07/12 5:49 PM

42 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

<order> <item price=”50” currency=”USD” name=”metal gear” /> <item price=”25” currency=”USD” name=”plastic gear” /> </order>

The following XQuery returns the sum:

sum(doc(‘orders.xml’)/order/item/@price)

For testing or learning XQuery, a handy online sandbox is: http://basex.org/products/ live-demo/.

JavaScript Object Notation (JSON) JSON was created in 2001 and came into use by Yahoo in 2005. JSON has few rules, few base types, and is human readable. JSON schema enables document validation, but this is rarely used. JSON is a great format for transmitting data between systems because it is simple, text based, and self-describing.

A person can be represented in JSON like this:

{ firstName : “David”, lastName : “Smith” }

One thing to watch out for is how dates are represented in JSON. There is no base type of date and there is no standard way to represent dates. It is recommended to represent dates using the International Standards Organization 8601 format. In ISO-8601 dates look like this: 1997-07- 16T19:20:30.45+01:00. Representing dates in ISO-8601 keeps them human readable, ensures programming languages can parse them, and keeps time zone information.

Choosing ISO-8601 as the default data interchange format for projects is a good idea. Using JSON will reduce the amount of time spent dealing with serialization issues.

Transferring Nontextual Data Both JSON and XML create human-readable text documents. What happens if a service needs to transmit or receive an image, a video, or a PDF document, such as a check image for a fi nancial service or a video clip for a public safety service? This type of nontextual data is called binary data. When transmitting binary data as text, it needs to be Base64 encoded so it can be represented with the rest of the data. Base64 encoding comes with two downsides. First, the size of the text representa- tion increases by 33 percent. Second, there is additional processing overhead by both the sender and receiver for encoding or decoding the Base64 data to binary and vice versa.

CREATING AN EXAMPLE WEB SERVICE Having talked about the technologies behind creating a consumable web service, this section shows how to create a consumable web service in a Linux Apache PHP environment, and three different service delivery technologies on the Microsoft .NET stack: WCF, OData, and ASP.NET MVC.

c03.indd 42c03.indd 42 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 43

Using the Microsoft Stack The .NET platform has a variety of technologies enabling the easy creation of consumable web services. This section walks through creating a database and sample data for the services to operate on. The rest of the section shows how to create the service in three .NET technologies: WCF, OData, and MVC.

Creating the Datastore The WCF, OData, and MVC walkthroughs later in this section all assume the database script from this section has been executed.

The example services will expose a simple data model consisting of two tables: Leagues and DerbyNames. Some of the Gravity Works staff are Roller Derby fans. They noticed the players had interesting names and decided their information (which is publicly available) would make a good example service.

Figure 3-1 shows a database diagram of the tables the script will create.

Open SQL Server Management Studio 2008 and connect to the local SQL Server instance running on the machine. Open a new query window and run the SQL-Server-Create- Derby-Database script (full SQL script can be found within the download section for this book at http://www.wrox.com) to create the tables and insert the data used for the rest of the walkthroughs:

After running the script, SQL Server Management Studio will display “Query Executed Successfully.” The walkthroughs in this section use this database to retrieve data.

Using Windows Communication Foundation Windows Communication Foundation (WCF) is a .NET Framework library designed for developers to create communication endpoints for software. Web services are software communication endpoints, so on the surface WCF seems like an ideal choice for creating consumable web services. Unfortunately, WCF is designed for a broad number of communication scenarios, and this broad set of capabilities introduces a lot of complexity that is not necessary for web services. For example, WCF supports reliable sessions, transactions, TCP, named pipes, Microsoft Message Queuing, activity tracing, and Windows Management Instrumentation.

This walkthrough assumes the following software is installed:

! ASP.NET 4.0

! Visual Studio 2010

! IIS 7.5

! Microsoft SQL Server 2008 R2

FIGURE 3#1: Database diagram

c03.indd 43c03.indd 43 28/07/12 5:49 PM28/07/12 5:49 PM

44 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

1. Open Visual Studio and select File # New Project to create a new project. 2. In the New Project template selection screen, open the Visual C# node and select the WCF

node.

3. From the WCF project types that display, select WCF Service Application. If that project type does not display, ensure the fi lter at the top of the dialog box is set to .NET Framework 4.

4. Set the project name to DerbyNamesService and click OK, as shown in Figure 3-2.

FIGURE 3#2: New WCF Service Application

For ease of database access this walkthrough uses LINQ to SQL. LINQ to SQL is an Object Relational Mapper technology that ships with the .NET Framework. Using LINQ requires an addi- tional project reference to System.Data.Linq.

To add the reference, right-click the References node of the DerbyNamesService project and select Add Reference.

In the Add Reference dialog box, fi nd System.Data.Linq and click the Add button as shown in Figure 3-3.

c03.indd 44c03.indd 44 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 45

After adding the System.Data.Linq reference, you need to create a class to access the data. To do this, right-click the DerbyNamesService project and choose Add # New Item as shown in Figure 3-4.

FIGURE 3#3: Add Reference dialog box

FIGURE 3#4: Add New Item

c03.indd 45c03.indd 45 28/07/12 5:49 PM28/07/12 5:49 PM

46 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

In the Add New Item dialog box, select Class, name it DerbyContext, and click the Add button as shown in Figure 3-5.

FIGURE 3#5: Add New Class

The DerbyContext class will provide the data. To represent the data as .NET objects, add two more code fi les: DerbyNames and Leagues. The DerbyNames class will contain the information on a derby player. Make the DerbyNames.cs fi le contain this code:

using System; using System.Data.Linq.Mapping;

namespace DerbyNamesService { [Table] public class DerbyNames { [Column(IsPrimaryKey = true)] public int DerbyNameId; [Column] public string Name; [Column]

c03.indd 46c03.indd 46 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 47

public string Number; [Column] public DateTime? DateAdded; [Column] public string League; } }

The Leagues class will contain information about the derby leagues, such as the league name. Make the Leagues.cs fi le contain this code:

using System.Data.Linq.Mapping;

namespace DerbyNamesService { [Table] public class Leagues { [Column(IsPrimaryKey=true)] public int LeagueId; [Column] public string LeagueName; [Column] public string URL; [Column] public string StateProvince; [Column] public string CountryCode; } }

The DerbyContext will be the class providing access to the database from the DerbyService class. Modify the DerbyContext.cs code to contain this code:

using System.Data.Linq; using DerbyNamesService;

namespace DerbyNamesService { public class DerbyContext : DataContext { public Table<DerbyNames> DerbyNames; public Table<Leagues> Leagues; public DerbyContext() : base(“Data Source=.;Initial Catalog=DerbyNames; User Id=webUser;Password=webuser;”) {

} } }

c03.indd 47c03.indd 47 28/07/12 5:49 PM28/07/12 5:49 PM

48 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

In the Visual Studio Solution Explorer, rename Service1.svc to DerbyService.svc and then rename IService1.cs to IDerbyService.cs. If Visual Studio prompts if you would like to rename all project references, click Yes. This step is just a cleanup step to rename the default fi les Visual Studio creates for you. The IDerbyService interface defi nes the contract for the service — in other words, this interface will expose the operations the service provides. Change the IDerbyService.cs fi le to contain the following code:

using System.Collections.Generic; using System.ServiceModel;

namespace DerbyNamesService { [ServiceContract] public interface IDerbyService { [OperationContract] public IEnumerable<DerbyNames> PlayerNames();

[OperationContract] public IEnumerable<Leagues> Leagues(); } }

With the service contract defi ned, a class to implement the operations defi ned by the IDerbyService contract needs to be created. The DerbyService.svc.cs fi le will implement the contract. In other words, the contract states what the service will do and the DerbyService actually does the work. Open the DerbyService.svc.cs fi le and replace the existing code with the following code:

using System.Collections.Generic; using System.Linq; using System.ServiceModel.Web;

namespace DerbyNamesService { public class DerbyNames : IDerbyNames { [WebGet(UriTemplate=”/PlayerNames”)] public DerbyName GetNames() { //get all the names from the database. var names = new DerbyContext().DerbyNames.ToList(); return names; }

[WebGet(UriTemplate=”/Leagues”)] public IEnumerable<Leagues> Leagues() { //Get all the leagues from the database. var leagues = new DerbyContext().Leagues.ToList(); return leagues; } } }

c03.indd 48c03.indd 48 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 49

Previously when Visual Studio asked to rename project references, it was only referring to C# code. The DerbyService.svc markup contains text that needs to be updated. To make the change Visual Studio missed, right-click the DerbyService.svc fi le and select View Markup as shown in Figure 3-6.

FIGURE 3#6: View Markup

Change the text Service=”DerbyNamesService.Service1” to Service=”DerbyNamesService .DerbyService” to match the class renaming you performed earlier. To make the service accessible it needs to be specifi ed in the web.config. In this context, the service endpoint is effectively a web- site to which you connect your client code. This site will receive communications from your client over HTTP, and return objects from your data source as text. To specify the service endpoint, insert the following XML as a child node of the system.servicemodel node:

<services> <service name=”DerbyNamesService.DerbyService”> <endpoint binding=”webHttpBinding” contract=”DerbyNamesService.IDerbyService”/> </service> </services>

c03.indd 49c03.indd 49 28/07/12 5:49 PM28/07/12 5:49 PM

50 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

To make the service return XML for easy consumption by mobile devices, insert the following XML as a child node of the behaviors node:

<endpointBehaviors> <behavior> <webHttp defaultOutgoingResponseFormat=”Xml”/> </behavior> </endpointBehaviors>

The fi nal web.config should look like this:

<?xml version=”1.0”?> <configuration> <system.web> <compilation debug=”true” targetFramework=”4.0” /> </system.web> <system.serviceModel> <services> <service name=”DerbyNamesService.DerbyService”> <endpoint binding=”webHttpBinding” contract=”DerbyNamesService.IDerbyService”/> </service> </services> <behaviors> <endpointBehaviors> <behavior> <webHttp defaultOutgoingResponseFormat=”Xml”/> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled=”true”/> <serviceDebug includeExceptionDetailInFaults=”false”/> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment multipleSiteBindingsEnabled=”true” /> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests=”true”/> </system.webServer> </configuration>

After all that work, the service is coded and confi gured. Click the solution and start debugging. Visual Studio will launch the ASP.NET Development Server and launch the system default browser with a URL similar to http://localhost:13610. The number is the port on which the ASP.NET Development Server is delivering requests. Add /DerbyService.svc/PlayerNames to the end of the URL to get the PlayerNames. Figure 3-7 shows the result in Google Chrome.

c03.indd 50c03.indd 50 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 51

With the service returning data, you can now have some fun! Using the Chrome Developer Tools will show the service response payload is 3.07KB. You can open the Chrome Developer Tools by using the keystroke Ctrl+Shift+I in Google Chrome. Figure 3-8 shows the Chrome Developer Tools network tab.

FIGURE 3#7: Player Names XML result

FIGURE 3#8: Chrome Developer Tools network view

c03.indd 51c03.indd 51 28/07/12 5:49 PM28/07/12 5:49 PM

52 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

An earlier section of this chapter discussed the differences in protocols. Change the protocol to JSON and see what happens. WCF makes this change easy. Open the web.config fi le and fi nd the webHttp node under the behavior node. Change the defaultOutgoingResponseFormat from XML to JSON. The node should look like this:

<webHttp defaultOutgoingResponseFormat=”Json”/>

Then rebuild the project and navigate back to the ASP.NET Development Server URL /DerbyService.svc/PlayerNames. On my machine, Chrome developer tools show the response size is now 2.22KB, which is a 28 percent reduction in size from the XML format. This reduction in size will result in faster transfer times, especially for larger data services. I recommended using JSON as the default data format and providing XML only if the requirements demand it.

The next improvement to make is getting URLs that make more sense. The URL /DerbyService .svc/PlayerNames doesn’t look nice. A better URL would be /RollerDerby/PlayerNames. ASP.NET routing is the easiest way to get the URL /RollerDerby/PlayerNames.

Routing is built into ASP.NET, but to get it to work with the service you need to add one reference. Expand the DerbyNameService project node, right-click References, and select Add Reference to bring up Add Reference dialog box. Select the .NET tab and fi nd System .ServiceModel.Activation. Click OK to add the System.ServiceModel.Activation assembly to the project as shown in Figure 3-9.

FIGURE 3#9: Add Reference dialog box

c03.indd 52c03.indd 52 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 53

Right-click the DerbyNames project and select Add New Item from the menu. From the Add New Item dialog box, select Global Application Class, and click the Add button to add it to the project as shown in Figure 3-10.

FIGURE 3#10: Add Global.asax dialog box

Find the Application_Start method within the Global.asax fi le and add the following line of code within the method:

RegisterRoutes(RouteTable.Routes);

Below the Application_Start method, add the following method:

private void RegisterRoutes(RouteCollection routes) { routes.Add(new ServiceRoute(“RollerDerby”, new WebServiceHostFactory(), typeof(DerbyService))); }

The RouteTable class is in the System.Web.Routing namespace. The WebServiceHostFactory and ServiceRoute classes are in the System.ServiceModel.Activation namespace. Add these using statements at the top of the fi le to resolve the references:

using System.Web.Routing; using System.ServiceModel.Activation;

c03.indd 53c03.indd 53 28/07/12 5:49 PM28/07/12 5:49 PM

54 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

For ASP.NET routing to work, WCF requests need to fl ow through ASP.NET. To turn this feature on, open the web.config fi le and fi nd the serviceHostingEnvironment element. Add the attribute aspNetCompatibilityEnabled=”true”. The serviceHostingEnvironment element should look like this:

<serviceHostingEnvironment multipleSiteBindingsEnabled=”true” aspNetCompatibilityEnabled=”true” />

ASP.NET routing also requires the service class be attributed stating it supports ASP.NET compatibility. To enable this, open the DerbyService.svc.cs class and add the AspNetCompatibilityRequirements attribute like this:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

The AspNetCompatibilityRequirements attribute is in the System.ServiceModel.Activation namespace, which requires the following using statement:

using System.ServiceModel.Activation;

After making those changes, compile and run the project. Navigate to the URL /RollerDerby/ PlayerNames and the same JSON document displayed in Figure 3-7 will display. Since I’m discussing nice-looking URLs (also known as friendly URLS), notice when giving a URL the service doesn’t understand such as /RollerDerby/THIS-PAGE-DOES-NOT-EXIST, the browser displays the strange looking page as shown in Figure 3-11.

FIGURE 3#11: A typical 404 page

Using Chrome Developer Tools shows the response has the correct 404 code. This is the same result when navigating to the root service: /RollerDerby. It would be better if missing pages were controlled by the DerbyService class. Fortunately, the WebGet attribute applied to the service methods gives control of the URLs.

c03.indd 54c03.indd 54 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 55

To deliver a 404 page that doesn’t expose the underlying technology as WCF, add the following method to the DerbyService class:

[WebGet(UriTemplate=”*”)] public void ErrorForGet() { throw new WebFaultException(HttpStatusCode.NotFound); }

The method name doesn’t matter. The functionality is coming from the UriTemplate parameter. The asterisk means if there isn’t a better match, run this attributed method for the request. The HttpStatusCode class is in the System.NET namespace, which requires the following using statement:

using System.Net;

Change the DerbyService class so it does not implement the IDerbyService. Because it is not using the IDerbyService, add the ServiceContract attribute to the DerbyService class, which requires the following using statement:

using System.ServiceModel;

The fi nal change to remove the response body is a web.config change. Find and remove the Services node along with its child service node. After rebuilding, running the application, and navigating to /RollerDerby/THIS-PAGE-DOES-NOT-EXIST, the page returns a 404 error with an empty body as shown in Figure 3-12:

FIGURE 3#12: A 404 page with an empty body

c03.indd 55c03.indd 55 28/07/12 5:49 PM28/07/12 5:49 PM

56 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

It is important for web services to be discoverable. Users may try to navigate to /RollerDerby. The service is currently confi gured to give a 404 error at that URL. It would help users to expose the PlayerName and Leagues operations of the service from the /RollerDerby URL so the users can fi nd the supported service operations.

To expose the services, open the DerbyService class and add the following method:

[WebGet(UriTemplate=””)] public Stream Root() { WebOperationContext.Current.OutgoingResponse.ContentType = “text/html”; string html = “<a href=\”PlayerNames\”>Player Names</a><br /><a” + “href=\”Leagues\”>Leagues</a>”; return new MemoryStream(Encoding.UTF8.GetBytes(html)); }

The Stream and MemoryStream classes are in the System.IO namespace, and the Encoding class is in the System.Text namespace. Add these two using statements:

using System.IO; using System.Text;

After building the project, running it, and navigating the browser to /RollerDerby, users are able to discover the operations the RollerDerby service provides. In Chrome, the page looks like Figure 3-13.

The fi nal code for the DerbyNamesService should look like this:

using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.ServiceModel; using System.ServiceModel.Activation; using System.ServiceModel.Web; using System.Text;

namespace DerbyNamesService { [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] [ServiceContract] public class DerbyService { [WebGet(UriTemplate=”/PlayerNames”)] public IEnumerable<DerbyNames> PlayerNames() { var names = new DerbyContext().DerbyNames.ToList(); return names; }

[WebGet(UriTemplate=”/Leagues”)]

FIGURE 3#13: Discoverable service URLs

c03.indd 56c03.indd 56 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 57

public IEnumerable<Leagues> Leagues() { var leagues = new DerbyContext().Leagues.ToList(); return leagues; }

[WebGet(UriTemplate = “*”)] public void ErrorForGet() { throw new WebFaultException(HttpStatusCode.NotFound); }

[WebGet(UriTemplate = “”)] public Stream Root() { WebOperationContext.Current.OutgoingResponse.ContentType = “text/html”; string html = “<a href=\”PlayerNames\”>Player Names</a><br /> <a href=\”Leagues\”>Leagues</a>”; return new MemoryStream(Encoding.UTF8.GetBytes(html)); } } }

The fi nal web.config should look like this:

<?xml version=”1.0”?> <configuration> <system.web> <compilation debug=”true” targetFramework=”4.0” /> </system.web> <system.serviceModel> <behaviors> <endpointBehaviors> <behavior> <webHttp defaultOutgoingResponseFormat=”Json”/> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled=”true”/> <serviceDebug includeExceptionDetailInFaults=”false”/> </behavior> </serviceBehaviors> </behaviors> <serviceHostingEnvironment multipleSiteBindingsEnabled=”true” aspNetCompatibilityEnabled=”true” /> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests=”true”/> </system.webServer> </configuration>

As shown in this section, WCF is a fl exible framework capable of delivering consumable web services to clients. The downside of using WCF for web services is the complexity of the technology stack. With all the fl exibility WCF provides, using it to deliver text data over HTTP is using only a small percentage of the framework.

c03.indd 57c03.indd 57 28/07/12 5:49 PM28/07/12 5:49 PM

58 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

Using Open Data Protocol (OData) The Open Data Protocol (OData) is a web protocol for querying and updating data in a standard way. OData has many querying capabilities such as getting the count, expanding related entities, paging, and many fi lter options. Read about the capabilities on http://www.odata.org. Microsoft created the technology and has released it under the Open Specifi cation Promise, which means Microsoft has granted everyone license to use the OData technology. OData is a great choice for web services that create, read, update, and delete data without complex business rules. OData has especially advanced querying capabilities that make it fl exible for many projects.

This walkthrough assumes the following software is installed:

! Visual Studio 2010

! IIS 7.5

! Entity Framework 4.0

! SQL Server 2008 R2

1. Open Visual studio and select File # New Project. 2. From the New Project menu, select ASP.NET Empty Web Application. 3. Name the service ODataDerbyService and click OK, as shown in Figure 3-14.

FIGURE 3#14: New Empty Web Application dialog box

c03.indd 58c03.indd 58 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 59

To deliver data from the service, this example uses Entity Framework. Entity Framework is an Object Relational Mapper that has been released by Microsoft. What that means is that it will bind your database to C# objects directly without the user needing to do any of the heavy lifting.

Right-click the ODataDerbyService project and select Add New Item.

From the Templates tree, fi nd Data and then select the ADO.NET Entity Data Model template. Enter DerbyData.edmx for the name and click the Add button as shown in Figure 3-15.

FIGURE 3#15: Add new ADO.NET Entity Data Model dialog box

On the fi rst screen of the Entity Data Model Wizard, select Generate from Database and click Next. On the next screen of the wizard, click the New Connection button. If you are connecting to SQL Server on the same machine as you are developing on it refer to it by the local instance address. For the server name enter a dot (.). For the database name select DerbyNames from the drop-down list. Then click OK as shown in Figure 3-16.

c03.indd 59c03.indd 59 28/07/12 5:49 PM28/07/12 5:49 PM

60 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

FIGURE 3#16: Database Connection Properties dialog box

After clicking OK on the Connection Properties dialog box, Visual Studio will be back in the Entity Data Model Wizard. Click Next to continue.

On the Choose Your Database Objects step of the wizard, check Tables, leave the rest of the settings at their defaults, and click Finish, as shown in Figure 3-17.

FIGURE 3#17: Data Model Wizard Choose Objects dialog box

c03.indd 60c03.indd 60 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 61

With the data model created, the next step is to add the OData service. Right-click the ODataDerbyService project and select Add New Item. From the Add New Item dialog box, in the Installed Templates tree select the Web node and then select WCF Data Service. Name it DerbyService.svc and then click the Add button as shown in Figure 3-18.

FIGURE 3#18: Add new WCF Data Service

Visual Studio has done almost all of the work to make OData expose the database as a web service. To make the service access the data model created earlier, open the DerbyService.svc.cs class and fi nd the comment /* TODO: put your data source class name here /*. Replace that com- ment with DerbyNamesEntities like this:

public class DerbyService : DataService<DerbyNamesEntities>

Now the service is connected to the data. However, by default OData doesn’t expose any of the data for security reasons. To expose the two tables from the model, uncomment this line:

config.SetEntitySetAccessRule(“MyEntityset”, EntitySetRights.AllRead);

and change the string “MyEntityset” to “*” like this:

config.SetEntitySetAccessRule(“*”, EntitySetRights.AllRead);

c03.indd 61c03.indd 61 28/07/12 5:49 PM28/07/12 5:49 PM

62 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

The fi nal DerbyService.svc.cs fi le should look like Figure 3-19.

FIGURE 3#19: The fi nal DerbyService.svc.cs fi le

That is all the confi guration required to confi gure an OData service. Build the project, run the project, and if Visual Studio doesn’t point the browser to the DerbyService.svc URL, navigate to /DerbyService.svc/. Figure 3-20 shows results in Google Chrome.

OData is showing DerbyNames and Leagues col- lections are available.

In the browser address bar add /DerbyNames after DerbyService.svc. The service responds with an XML document showing the DerbyNames from the database. Notice the DerbyNames XML document isn’t color coded — this is because the content type request header is application/ atom+xml instead of application/xml. OData uses the Atom and AtomPub format to represent collections. Also notice the DerbyNames XML

FIGURE 3#20: Chrome displaying service results

c03.indd 62c03.indd 62 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 63

document has links like <id>http://localhost:25457/DerbyService.svc/DerbyNames(1)</ id>. That link is to the URL showing the DerbyName with a primary key of 1. This starts to show the power of OData. OData provides many querying capabilities. The document is telling consum- ers how to query the service for a particular instance of a collection item.

To expand upon the querying capabilities, enter this URL:

/DerbyService.svc/DerbyNames?$filter=League%20eq%20’Lansing%20Derby%20Vixens’

The query string is telling the OData service to return items from the DerbyNames collection where League is equal to “Lansing Derby Vixens.” OData responds by returning all the players in the system from the Lansing Derby Vixens league as shown in Figure 3-21.

FIGURE 3#21: Chrome displaying query results

OData does have the capability to return JSON. Unfortunately, the WCF Data Services implementa- tion does not implement the $format query parameter specifi ed in the OData specifi cation. Instead, the WCF Data Services implementation responds with JSON only when the HTTP accept request header is set to “application/json”. Unfortunately, some programming platforms do not support changing request headers. The following procedure shows how to make the service return JSON without modifying the request headers on the client.

c03.indd 63c03.indd 63 28/07/12 5:49 PM28/07/12 5:49 PM

64 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

First, the service code needs to have access to all incoming requests before the requests are put into the OData pipeline. To get access to the requests, right-click the ODataDerbyService project and select Add New Item. In the Add New Item dialog box Installed Template tree, select Web. From the Templates select Global Application Class. Click the Add button to create the codefi le in the project as shown in Figure 3-22.

FIGURE 3#22: Add New Global Application Class dialog box

The Global class has a method named Application_BeginRequest, which is called when an HTTP request enters the application. This is a good spot to change the HTTP accept request header before WCF Data Services processes the request. To change the request header, insert the following line in the Application_BeginRequest method:

protected void Application_BeginRequest(object sender, EventArgs e) { HttpContext.Current.Request.Headers[“accept”] = “application/json”; }

Unfortunately, the ASP.NET Development Server does not allow modifying the request headers, but IIS 7.5 does. For this method to work in the debug environment requires using IIS Express instead of the ASP.NET Development Server. To change the environment, right-click the ODataDerbyService project and click Properties. From the properties window navigation tree select the Web tab. In the Web tab fi nd the Servers section and select the radio button for Use Local IIS Web Server. Mark the Use IIS Express checkbox and accept the Project URL, as shown in Figure 3-23.

c03.indd 64c03.indd 64 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 65

FIGURE 3#23: ODataDerbyService Project Properties dialog box

Close the property window to save the changes. Build the project, run it, and change the browser URL to /DerbyService.svc/DerbyNames?$filter=League%20eq%20’Lansing%20Derby%20 Vixens’.

The document is now returned in JSON instead of XML as shown in Figure 3-24.

FIGURE 3#24: Chrome showing JSON result

c03.indd 65c03.indd 65 28/07/12 5:49 PM28/07/12 5:49 PM

66 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

For this query, changing the format to JSON resulted in a 75 percent reduction in the size of the document.

OData also enables inserting and updating data. Open the DerbyService.svc.cs fi le and change the config.SetEntitySetAccessRule second parameter from EntitySetRights.AllRead to EntitySetRights.All. This will make all data in all tables readable and writable. To set rights on a specifi c table use a line like this: config.SetEntitySetAccessRule(“tableName”, EntitySetRights.All);

To insert a player name, submit the following HTTP request programmatically or using a tool like Fiddler (discussed in the later “Debugging” section):

POST http://localhost:25457/DerbyService.svc/DerbyNames HTTP/1.1 User-Agent: Fiddler Host: localhost:25457 content-type: application/json Content-Length: 108

{“Name”:”gravityworks”, “Number”:”infinity”, “League”:”Lansing Derby Vixens”, “DateAdded”: “2012/04/30” }

OData is a great choice for applications that are dealing with CRUD operations. Instead of writing boilerplate code to read, update, delete, and insert data, OData gives a robust set of operations with little work.

Using ASP.NET MVC 3 ASP.NET MVC is a web framework released by Microsoft. It follows the model-view-controller pat- tern. This separation provides benefi ts such as easy testability and providing different views of the same model. These features make ASP.NET MVC a great choice for creating web services.

This walkthrough assumes the following software is installed:

! ASP.NET 4.0

! ASP.NET MVC 3

! Visual Studio 2010

! IIS 7.5

! Microsoft SQL Server 2008 R2

To get started you need a project. Open Visual Studio and select File # New Project. From the New Project dialog box, select the Web node from the Installed Templates tree and then select ASP.NET MVC3 Web Application. Name the project MVCDerbyService and click OK to create the project as shown in Figure 3-25.

c03.indd 66c03.indd 66 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 67

On the New ASP.NET MVC 3 Project Template dialog box, select Internet Application, set the view engine to Razor, and check the Use HTML5 Semantic Markup checkbox. Then click OK to continue. Figure 3-26 shows the confi guration screen with the options for this walkthrough.

FIGURE 3#25: Create new ASP.NET MVC 3 Web Application Project dialog box

FIGURE 3#26: New ASP.NET MVC 3 Project Template dialog box

c03.indd 67c03.indd 67 28/07/12 5:49 PM28/07/12 5:49 PM

68 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

For ease of database access this walkthrough uses LINQ to SQL. Using LINQ to SQL requires an additional project reference to System.Data.Linq. To add the reference, right-click the References node of the DerbyNamesService project and select Add Reference. In the Add Reference dialog box click the .NET tab, fi nd System.Data.Linq, and click the Add button as shown in Figure 3-27.

FIGURE 3#27: Add Reference dialog box

After adding the System.Data.Linq reference, you need to create a class to access the data. To add the data access class, fi nd the Models folder in the Solution Explorer. Right-click the Models folder and select Add New Item as shown in Figure 3-28.

c03.indd 68c03.indd 68 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 69

In the Add New Item dialog box, select the Web node from the Installed Templates tree. Then select Class from the Templates, name it DerbyContext, and click the Add button as shown in Figure 3-29.

FIGURE 3#28: Add New Item menu

FIGURE 3#29: Add New Class dialog box

c03.indd 69c03.indd 69 28/07/12 5:49 PM28/07/12 5:49 PM

70 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

The DerbyContext class will provide the data. To represent the data as .NET objects, add two more code fi les, DerbyNames and Leagues, in the Models folder.

The DerbyNames class will contain the information on a derby player. Make the DerbyNames.cs fi le contain this code:

using System; using System.Data.Linq.Mapping; namespace MVCDerbyService.Models { [Table] public class DerbyNames { [Column(IsPrimaryKey = true)] public int DerbyNameId; [Column] public string Name; [Column] public string Number; [Column] public DateTime? DateAdded; [Column] public string League; } }

The Leagues class will contain information about the derby leagues, such as the league name. Make the Leagues.cs fi le contain this code:

using System.Data.Linq.Mapping;

namespace MVCDerbyService.Models { [Table] public class Leagues { [Column(IsPrimaryKey = true)] public int LeagueId; [Column] public string LeagueName; [Column] public string URL; [Column] public string StateProvince; [Column] public string CountryCode; } }

The DerbyContext will be the class providing access to the database from the DerbyService class. Modify the DerbyContext.cs code to contain this code:

c03.indd 70c03.indd 70 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 71

using System.Data.Linq;

namespace MVCDerbyService.Models { public class DerbyContext : DataContext { public Table<DerbyNames> DerbyNames; public Table<Leagues> Leagues; public DerbyContext() : base(“Data Source=.;Initial Catalog=DerbyNames; User Id=webUser;Password=webuser;”) { } } }

MVC uses a concept called a controller to route requests. To create a request endpoint, right-click the Controllers folder and select Add Controller, as shown in Figure 3-30.

FIGURE 3#30: Add New Controller context menu

In the Add Controller dialog box, name the controller DerbyServiceController and select the Empty controller template.

Modify DerbyServiceController.cs to contain the following code:

c03.indd 71c03.indd 71 28/07/12 5:49 PM28/07/12 5:49 PM

72 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MVCDerbyService.Models;

namespace MVCDerbyService.Controllers { public class DerbyServiceController : Controller { public ActionResult DerbyNames() { DerbyContext dc = new DerbyContext(); List<DerbyNames> names = dc.DerbyNames.ToList(); return Json(names, JsonRequestBehavior.AllowGet); } } }

One controller class with one method is all MVC requires to create an HTTP endpoint. Build and run the project. Visual Studio will open a web browser with a localhost URL. Add /DerbyService/ DerbyNames to run the preceding code. The results in Chrome are shown in Figure 3-31.

Figure 3-31 shows MVC correctly set the content type to application/json.

FIGURE 3#31: Chrome displaying the content type

c03.indd 72c03.indd 72 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 73

What if the service needs to return XML? It would be nice to have an XmlResult class provid- ing functionality similar to the JsonResult class. Unfortunately, MVC does not ship with an XmlResult class, but we can easily build one.

The DerbyNames method is returning a JsonResult, which is a type of ActionResult. To create an XmlResult class, fi rst add a Results folder to the MVCDerbyService project to keep the project well organized.

Right-click the Results folder and add a new class named XmlResult. The contents of the XmlResult class should look like this:

using System.Web.Mvc; using System.Xml.Serialization;

namespace MVCDerbyService.Results { public class XmlResult : ActionResult { private object payload { get; set; }

public XmlResult(object data) { payload = data; }

public override void ExecuteResult(ControllerContext context) { XmlSerializer serializer = new XmlSerializer(payload.GetType()); context.HttpContext.Response.ContentType = “text/xml”; serializer.Serialize(context.HttpContext.Response.Output, payload); } } }

MVC uses routes to match incoming request URLs to the appropriate controller. To enable return- ing XML, open the Global.asax.cs fi le in the root of the solution. Find the RegisterRoutes method and add routes.MapRoute(“format”,”{controller}/{action}.{format}”); between the two existing route statements.

public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);

routes.MapRoute( “format”, “{controller}/{action}.{format}”);

routes.MapRoute( “Default”, // Route name “{controller}/{action}/{id}”, // URL with parameters new { controller = “Home”, action = “Index”, id = UrlParameter.Optional } // Parameter defaults ); }

c03.indd 73c03.indd 73 28/07/12 5:49 PM28/07/12 5:49 PM

74 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

With the route in place it is time to change the controller to respond to the format information. Open the DerbyServiceController.cs fi le and modify it like this:

using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MVCDerbyService.Models; using MVCDerbyService.Results;

namespace MVCDerbyService.Controllers { public class DerbyServiceController : Controller { public ActionResult DerbyNames(string format) { DerbyContext dc = new DerbyContext(); List<DerbyNames> names = dc.DerbyNames.ToList(); if (string.Compare(format, “xml”) == 0) { return new XmlResult(names); } return Json(names, JsonRequestBehavior.AllowGet); } } }

After building and running the project, navigating to /DerbyService/DerbyNames.xml displays the same document in XML instead of JSON.

This approach of specifying the format in the URL works and provides advantages, for example being able to have anchor links to PDF and comma separated value (CSV) representations, but the HTTP specifi cation has MIME types for content negotiation. Content negotiation enables the client to request the information as well as the format of the information. For example, web browsers request text/html. For correctness and expected behavior the service should return HTML, XML, or JSON depending on what the client requests in the accept header. If the service does not support the requested type, the service should return a 406 error code specifying the valid values for the header, such as HTML, XML, and JSON.

Supporting different request headers will require a new result class. Add an AcceptHeaderResult class in the Results folder. Open the AcceptHeaderResult.cs fi le and replace the generated fi le contents with the following code:

using System.Web.Mvc;

namespace MVCDerbyService.Results { public class AcceptHeaderResult : ActionResult { private object payload { get; set; }

public AcceptHeaderResult(object data) {

c03.indd 74c03.indd 74 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 75

payload = data; }

public override void ExecuteResult(ControllerContext context) { string accept = context.HttpContext.Request.Headers[“accept”].ToLower();

ActionResult result = null; if (accept.Contains(“text/html” )) { context.Controller.ViewData.Model = payload; result = new ViewResult() { TempData = context.Controller.TempData, ViewData = context.Controller.ViewData }; } else if (accept.Contains(“application/json”)) { result = new JsonResult() { Data = payload, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } else if (accept.Contains(“text/xml”)) { result = new XmlResult(payload); } else { result = new HttpStatusCodeResult(406, “Type not supported.”); } result.ExecuteResult(context); } } }

To use the new AcceptHeaderResult class you need to modify the DerbyService controller to use it. Modify the DerbyServiceController.cs fi le like this:

using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MVCDerbyService.Models; using MVCDerbyService.Results;

namespace MVCDerbyService.Controllers { public class DerbyServiceController : Controller { public ActionResult DerbyNames() { DerbyContext dc = new DerbyContext(); List<DerbyNames> names = dc.DerbyNames.ToList(); return new AcceptHeaderResult(names); } } }

c03.indd 75c03.indd 75 28/07/12 5:49 PM28/07/12 5:49 PM

76 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

Using a tool like Fiddler (discussed in the next section) enables you to modify the application head- ers to test the XML and JSON responses. To get the same JSON response from before, issue the fol- lowing HTTP request:

GET http://localhost:33008/DerbyService/DerbyNames HTTP/1.1 Host: localhost:33008 Accept: application/json

To make the system respond with the unsupported error code, issue the following HTTP request:

GET http://localhost:33008/DerbyService/DerbyNames HTTP/1.1 Host: localhost:33008 Accept: invalid

On the ASP.NET Development Server, the nice message specifying the supported types of text/html, text/xml, and application/json is not displayed. The message text displays on IIS 7.5 and IIS Express.

This gives a nice framework to easily add new endpoints. To add the Leagues endpoint, add the fol- lowing method to the DerbyServiceController.cs fi le:

public ActionResult Leagues() { DerbyContext dc = new DerbyContext(); List<Leagues> names = dc.Leagues.ToList(); return new AcceptHeaderResult(names); }

Adding that code snippet makes the JSON and XML HTTP requests work correctly. To add the HTML view, fi nd the DerbyService folder underneath the Views folder. Right-click the DerbyService folder and select Add View. Name the view Leagues.

Open the Leagues.cshtml fi le and modify it as shown in the following code snippet:

<h2>Leagues</h2>

@foreach (var item in @Model) { <div> <span>@item.StateProvince</span> - <span>@item.LeagueName</span> </div> }

To make this service discoverable, add content at /DerbyService. This requires a change to the DerbyServiceController and an additional view. In the DerbyService subfolder of the Views folder, add a new view named Index. Put the following code in the view:

@{ ViewBag.Title = “Index”; }

<h2>Index</h2>

c03.indd 76c03.indd 76 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 77

<div> @Html.ActionLink(“DerbyNames”, “DerbyNames”) </div> <div> @Html.ActionLink(“Leagues”, “Leagues”) </div>

After adding the index fi le you need to hook it up. To enable the endpoint, open DerbyServiceController.cs and add the following method:

public ActionResult Index() { return View(); }

After making those changes, navigating to /DerbyService shows a link for DerbyNames and a link for Leagues.

This section has shown how easy it is to create a consumable service in ASP.NET MVC. The technology is geared toward making websites, but the extensible and pluggable nature of the technology makes it a great choice for creating consumable services.

Using the Linux Apache MySQL PHP (LAMP) Stack Web services are cross platform. This section shows how to confi gure a web server on Linux to retrieve data from a MySQL database and leverage a technology called OData to deliver querying functionality with little work. OData is a web platform that enables create, read, update, and delete operations over HTTP. OData is used to expose information from systems such as relational database, fi le systems, and traditional websites using existing web technologies such as HTTP, XML, and JSON. Think of it as exposing parts of your database to the World Wide Web.

This walkthrough assumes the following software is installed:

! Ubuntu 11.10

! Apache2 with URL rewrite mode

! PHP-5.4

! MySQL

! Symfony 2.0

! PHP5s XSL extension

! PHP Extension and Application Repository (PEAR)

To use OData on MySQL, fi rst you need a data source, meaning someplace where the data is contained. Download the fi le named MySQL-Create-DerbyNames-Database.sql from the download section for this book at http://www.wrox.com. This document contains a script that will create the DerbyNames database, which consists of a leagues table and a derby names table.

c03.indd 77c03.indd 77 28/07/12 5:49 PM28/07/12 5:49 PM

78 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

To execute the script from a terminal, run the following command to log into the MySQL admin console:

mysql -u root -p

Enter the root password when MySQL prompts for a password.

From the MySQL command prompt, execute the script by entering the following command:

source DerbyNames.sql

After creating the database, the next task is to download the OData Producer Library for PHP. The OData Producer Library is software that will expose the MySQL database as an OData source. Download it from http://odataphpproducer.codeplex.com/.

Unzip the fi le contents and copy the OData Producer Library fi les to /var/www/OData and ensure the /var/www/OData directory has an Index.php fi le.

Next, PHP needs to know where the OData library is located. To confi gure PHP to look for the OData Producer Library for PHP, create an OData.ini fi le in /etc/php5/conf.d$. After creating the fi le, type in the following line of code and save the fi le:

include_path = “:/var/www/Odata:/var/www/OData/library”;

For the OData library to handle a request, Apache needs to hand the request to OData. By default, on the Microsoft Windows .NET stack OData services end in .svc. To keep that convention on this Apache confi guration, modify /var/etc/apache2/httpd.conf by adding these lines:

<Directory “/var/www”> <IfModule mod_rewrite.c> RewriteEngine on RewriteRule (\.svc.*) OData/Index.php </IfModule> </Directory>

The OData Connector for MySQL will examine a MySQL database and produce all the PHP code fi les necessary for read-only OData operations except one — the OData connector for MySQL does not create the code for IDataServiceStreamProvider. IDataServiceStreamProvider is used to deliver binary data, for example an image or a video, through the OData Producer Library.

The OData Connector for MySQL requires a specifi c piece of software called Doctrine Object Relational Mapper. This software is an Object Relational Mapper (ORM). For those unfamiliar with it, an ORM represents database tables as programming language objects.

Using the PEAR package manager, the Doctrine Object Relational Mapper can be installed using the following commands:

sudo pear channel-discover pear.doctrine-project.org sudo pear install doctrine/DoctrineORM

With the prerequisite ORM installed, it is time to download the OData Connector for the MySQL library. The OData Connector library is built to generate PHP code fi les to perform OData

c03.indd 78c03.indd 78 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 79

operations against a MySQL source. You can download the package from http://odatamysqlph- pconnect.codeplex.com. The following steps are for V 1.0.

Navigate to the directory the package downloaded to and unzip it. Open a terminal and navigate to the unzipped package directory.

To generate the code fi les, execute the following command:

php MySQLConnector.php /db=DerbyService /srvc=DerbyService /u=webUser /pw=webuser /h=localhost

Running the MySQLConnector.php script states:

EDMX file is successfully generated in the output folder. Do you want to modify the EDMX file-/home/smithd98/Downloads/MySQLConnectorV1.0 /ODataConnectorForMySQL/OutputFiles/Northwind/NorthwindEDMX.xml(y/n):

Press N and the Return key to indicate no.

The terminal will print the following success messages:

MetadataProvider class has generated Successfully. QueryProvider class has generated Successfully. DataServiceProvider class has generated Successfully. DSExpressionProvider class has generated Successfully. Service.config file has generated Successfully.

Copy the generated fi les into the /var/www/OData/services/DerbyNames directory with the fol- lowing two commands:

sudo mkdir /var/www/OData/services/DerbyNames sudo cp ~/Downloads/MySQLConnectorV1.0/ODataConnectorForMySQL /OutputFiles/DerbyNames/* /var/www/OData/services/DerbyNames/

One of the fi les generated by the MySQLConnector script is service.config.xml. This fi le specifi es the confi guration information to correctly activate the service. Unfortunately, the service.config.xml fi le generated doesn’t work correctly on Linux. To work on Linux it needs to be modifi ed slightly.

The contents of the /var/www/OData/services/DerbyNames/service.config.xml fi le generated by the library are:

<?xml version=”1.0”?> <configuration> <services> <Service Name=”DerbyNames.svc”> <path>Services\DerbyNames\DerbyNamesDataService.php</path> <classname>DerbyNamesDataService</classname> <baseURL>/DerbyNames.svc</baseURL> </Service> </services> </configuration>

c03.indd 79c03.indd 79 28/07/12 5:49 PM28/07/12 5:49 PM

80 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

The contents of the /var/OData/services/DerbyNames/service.config.xml Service element need to be copied into the /var/www/OData/services/service.config.xml services element as a child element.

After copying it in there, you need to make some slight changes:

1. Change the Service node to lowercase. 2. Replace the backslash (\) in the path node with a forward slash (/) so the paths are valid on

Linux.

3. Change Services to lowercase in the path node.

After making those changes, the fi le should look like this:

<?xml version=”1.0”?> <configuration> <services> <service Name=”DerbyNames.svc”> <path>services/DerbyNames/DerbyNamesDataService.php</path> <classname>DerbyNamesDataService</classname> <baseURL>/DerbyNames.svc</baseURL> </service> </services> </configuration>

Use a web browser to navigate to http://localhost/DerbyNames.svc/DerbyNames. Firefox will display an XML document, as shown in Figure 3-32.

FIGURE 3#32: Firefox display of the XML document from the service

c03.indd 80c03.indd 80 28/07/12 5:49 PM28/07/12 5:49 PM

Creating an Example Web Service " 81

If the browser displays an error like this:

Warning: Cannot modify header information - headers already sent by (output started at /var/www/OData/services/DerbyNames/ DerbyNamesQueryProvider.php:390 in /var/www/OData/Dispatcher.php on line 205

edit the fi le /var/www/OData/services/DerbyNames/DerbyNamesQueryProvider.php by removing line 326. In the version I have there is a bug putting an empty line at the end of the fi le (after the ?>).

Save the fi le and then reload http://localhost/DerbyNames.svc/DerbyNames in the browser. The XML document shown in Figure 3-32 should display.

With everything working correctly it is time to take advantage of OData features! First, use JSON instead of XML to reduce the size of the data returned by the OData service calls. To change the format to JSON, use the following URL:

http://localhost/DerbyNames.svc/DerbyNames?$format=json

This time the browser displays the raw JSON, as shown in Figure 3-33.

FIGURE 3#33: JSON output from service

c03.indd 81c03.indd 81 28/07/12 5:49 PM28/07/12 5:49 PM

82 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

Another feature of OData is that it enables querying data over HTTP. To query the service for all the players in the Lansing Derby Vixens league, enter the following URL in the Firefox web browser:

http://localhost/DerbyNames.svc/DerbyNames?$filter=Leagues eq ‘Lansing Derby Vixens’&$format=json

Firefox displays the only two players in the database from the Lansing Derby Vixens League, as shown in Figure 3-34.

FIGURE 3#34: Filtered JSON data

OData enables developers to quickly expose read, write, update, and delete operations through web services. This chapter touched a bit on OData’s querying capabilities. The querying capabilities would take many hours of development time to get the same functionality OData provides. These querying capabilities make the service fl exible, which speeds up development because the service doesn’t need to be constantly modifi ed to meet new requirements. To learn more about the OData specifi cation and features that were not shown in this chapter, visit http://odata.org.

c03.indd 82c03.indd 82 28/07/12 5:49 PM28/07/12 5:49 PM

Debugging Web Services " 83

This section walked through creating a sample database, confi guring Apache for OData, installing the OData library, and confi guring the OData library. OData is a good choice to use for web services that need to provide create, read, update, and delete (CRUD) operations because it provides so much functionality and fl exibility for such a small effort.

DEBUGGING WEB SERVICES Despite your best intentions, all developers are not perfect and the web service you create will not work exactly correct the fi rst time you try to test it. This section discusses methods to fi gure out what is going wrong.

Tools Understanding why a web service is not working correctly can be diffi cult because most of the code running is standard software and not code written by you or your team. Most of the code delivering web services consists of the libraries being leveraged, the platform the code is running on, the web server code running, and the operating system code.

Fiddler When debugging web services, it is important to have the capability to see the raw requests and responses. Fiddler is a free Windows tool that does just that. Find installation instructions and the download at http://www.fiddler2.com.

Fiddler shows the raw HTTP traffi c for the Windows system on which it is running. This means the tool will show the raw HTTP service request and HTTP response if the system running Fiddler is the one making the request. Unfortunately, when developing mobile applications, Fiddler will not be able to show the HTTP traffi c because it is coming from an external device. Fiddler has another feature called Composer that allows the creation and execution of a raw HTTP request. The Composer feature enables testing and debugging of services. Getting the request and response to behave as expected is often the fi rst place I start when debugging a misbehaving web service. I confi gure the Fiddler request builder to go against my localhost, which also enables me to set breakpoints in my code. After the request and response are working correctly, I ensure my code is passing data that matches what I’ve produced in Fiddler.

The two most important features of using Fiddler to debug web services successfully are the fi lters and Composer. When Fiddler is running it captures all the HTTP traffi c on the machine on which it is running. This is typically too much data, which obscures the web calls that are important. Fiddler has the concept of fi lters, which enable a user to hide HTTP traffi c that is not of interest. I usually use the Hosts fi lter to show only traffi c from localhost and http://www.GravityWorksDesign.com as shown in Figure 3-35.

c03.indd 83c03.indd 83 28/07/12 5:49 PM28/07/12 5:49 PM

84 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

The other feature I use all the time is Composer. Composer enables putting together the exact HTTP request to have executed. This is useful for understanding why a web service call isn’t working, especially requests that use HTTP accept headers, because those requests cannot be executed by a default web browser.

Figure 3-36 shows using Fiddler to build an HTTP POST request to add a player to the WCF service created earlier in the chapter.

FIGURE 3#35: Fiddler Filters tab

FIGURE 3#36: Fiddler Composer tab

c03.indd 84c03.indd 84 28/07/12 5:49 PM28/07/12 5:49 PM

Debugging Web Services " 85

Fiddler is a must-have tool for debugging on the Windows platform.

Wireshark and MAC HTTP Client When developing services on the Macintosh platform I use the Mac HTTP client to test web service requests. Unfortunately, it does not capture traffi c like Fiddler. When I need to capture traffi c on Macintosh or Linux platforms I turn to Wireshark (http://www.wireshark.org/download.html), a free, open source debugging tool that is much more advanced than Fiddler or the Mac HTTP client. Wireshark is an advanced packet analysis tool used for HTTP traffi c analysis as well as any other network traffi c, such as debugging IP phones. For my simple needs of just debugging HTTP web calls, the additional features and complexity of Wireshark make it harder for me to use. For those not developing web services on the Windows platform, Wireshark will be a crucial tool. Figure 3-37 shows Wireshark in action on Linux.

FIGURE 3#37: Wireshark in action on Linux

Advanced Web Service Techniques This section covers two advanced web service techniques: Web Sockets and Web Service Callbacks. These techniques are not required for consumable web services, but can help services run effi ciently.

c03.indd 85c03.indd 85 28/07/12 5:49 PM28/07/12 5:49 PM

86 " CHAPTER 3 CREATING CONSUMABLE WEB SERVICES FOR MOBILE DEVICES

Web Sockets The HTTP protocol is designed for servers to respond to client requests. The client asks for a resource and the server delivers that resource. A problem arises if the server wants to deliver a resource to the client. For example, a stock viewing site like http://www.google.com/finance?q=p would be more valuable if it were able to update data on the client when the stock data changes. Today the most supported way to do this is by having the client continually ask the server “Do you have any new data for me?” This is wasteful because oftentimes the answer is no. That method is known as polling. Using Web Sockets a web server is able to deliver new data to the client without the client having to ask for the new information.

As of this writing Web Sockets are an emerging technology that not all browsers support. As support becomes more mainstream, web applications for things like e-mail, weather, traffi c information, and so on will benefi t from the ability for servers to notify clients when there is more current information.

Web Service Callbacks Sometimes a web service needs to call another one after it is fi nished. For example, if a web service is exposed that delivers faxes, the fax will take a long time to send. When submitting the fax request, the calling service should make the request and then disconnect instead of waiting for the result. However, the calling service eventually needs to know the result of the fax. To enable this web service, callbacks are used. Consider the following POST request:

POST http://faxservice.com/fax/000123456 HTTP/1.1 Host: faxservice.com content-type: application/json Content-Length: 107

{ “faxId”: “9839384”, “OnComplete”: “http://www.gravityworksdesign.com/faxresultreceiver”, “MessageBody”:”sending a fax” }

The requester submits that HTTP POST request to inform the fax service to make a fax to 000123456. After the fax service executes that request and gets a result, it calls the OnComplete service at http://www.EXAMPLE.com/faxresultreceiver passing the result and the faxId. This enables the original requester to match that faxId and result with the request it initiated.

SUMMARY This chapter covered a lot of ground. Initially the chapter discussed overall web service concepts before diving into specifi c implementations of example services on a variety of technologies. The fi rst walkthrough created an OData web service on the Linux platform. The next set of walkthroughs focused on three Microsoft technologies on the Windows platform: WCF, OData, and ASP.NET MVC.

c03.indd 86c03.indd 86 28/07/12 5:49 PM28/07/12 5:49 PM

Summary " 87

After understanding the walkthroughs, you learned that OData is a good choice for creating CRUD services without complex business logic very quickly. You have learned WCF provides a lot of functionality and customization, but much of it is not needed for web services. You have learned ASP.NET MVC is a great platform for developing web services with complex business logic, because it provides extreme fl exibility without complex features getting in the way.

The chapter wrapped up by discussing techniques for debugging services and some advanced web service techniques. The service implementations are intended to give readers a good starting point for creating consumable web services which will work for mobile applications and other applications.

Now that you know how to design and implement web services, the next chapter discusses mobile user interface design. The chapter focuses on issues like effective use of screen real estate, accessibility, and designing for the different platforms.

c03.indd 87c03.indd 87 28/07/12 5:49 PM28/07/12 5:49 PM