Web Services in Microsoft Azure

Exclusive offer: get 50% off this eBook here
Microsoft Azure: Enterprise Application Development

Microsoft Azure: Enterprise Application Development — Save 50%

Straight talking advice on how to design and build enterprise applications for the cloud using Microsoft Azure with this book and eBook

$26.99    $13.50
by Nathan A. Duchene Richard J. Dudley | November 2010 | Enterprise Articles Microsoft

Technically, web services are part of the web role, but their use and development are so distinctly different than web forms that we'll look at these separately. The web services themselves can be written in any language supported by Azure, but utilizing the Windows Communication Foundation (WCF) libraries in .NET greatly simplifies the development of web services. The simple storage services have their own REST API and client library developed, but if we want to add data into SQL Azure, we'll have to create our own web services.

In this article by Richard J. Dudley and Nathan A. Duchene, authors of Microsoft Azure: Enterprise Application Development, we'll:

  • Gain an overview of WCF services
  • Build the WCF service for the Jupiter Motors portal

 

Microsoft Azure: Enterprise Application Development

Microsoft Azure: Enterprise Application Development

Straight talking advice on how to design and build enterprise applications for the cloud

  • Build scalable enterprise applications using Microsoft Azure
  • The perfect fast-paced case study for developers and architects wanting to enhance core business processes
  • Packed with examples to illustrate concepts
  • Written in the context of building an online portal for the case-study application

 

        Read more about this book      

Web services and WCF

A web service is not one single entity and consists of three distinct parts:

  • An endpoint, which is the URL (and related information) where client applications will find our service
  • A host environment, which in our case will be Azure
  • A service class, which is the code that implements the methods called by the client application

A web service endpoint is more than just a URL. An endpoint also includes:

  • The bindings, or communication and security protocols
  • The contract (or promise) that certain methods exist, how these methods should be called, and what the data will look like when returned

A simple way to remember the components of an endpoint is A/B/C, that is, address/bindings/contract.

Web services can fill many roles in our Azure applications—from serving as a simple way to place messages into a queue, to being a complete replacement for a data access layer in a web application (also known as a Service Oriented Architecture or SOA). In Azure, web services serve as HTTP/HTTPS endpoints, which can be accessed by any application that supports REST, regardless of language or operating system.

The intrinsic web services libraries in .NET are called Windows Communication Foundation (WCF). As WCF is designed specifically for programming web services, it's referred to as a service-oriented programming model. We are not limited to using WCF libraries in Azure development, but we expect it to be a popular choice for constructing web services being part of the .NET framework. A complete introduction to WCF can be found at http://msdn.microsoft.com/en-us/netframework/aa663324.aspx.

When adding WCF services to an Azure web role, we can either create a separate web role instance, or add the web services to an existing web role. Using separate instances allows us to scale the web services independently of the web forms, but multiple instances increase our operating costs. Separate instances also allow us to use different technologies for each Azure instance; for example, the web form may be written in PHP and hosted on Apache, while the web services may be written in Java and hosted using Tomcat. Using the same instance helps keep our costs much lower, but in that case we have to scale both the web forms and the web services together. Depending on our application's architecture, this may not be desirable.

Securing WCF

Stored data are only as secure as the application used for accessing it. The Internet is stateless, and REST has no sense of security, so security information must be passed as part of the data in each request. If the credentials are not encrypted, then all requests should be forced to use HTTPS. If we control the consuming client applications, we can also control the encryption of the user credentials. Otherwise, our only choice may be to use clear text credentials via HTTPS.

For an application with a wide or uncontrolled distribution (like most commercial applications want to be), or if we are to support a number of home-brewed applications, the authorization information must be unique to the user. Part of the behind-the-services code should check to see if the user making the request can be authenticated, and if the user is authorized to perform the action. This adds additional coding overhead, but it's easier to plan for this up front.

There are a number of ways to secure web services—from using HTTPS and passing credentials with each request, to using authentication tokens in each request. As it happens, using authentication tokens is part of the AppFabric Access Control, and we'll look more into the security for WCF when we dive deeper into Access Control.

Jupiter Motors web service

In our corporate portal for Jupiter Motors, we included a design for a client application, which our delivery personnel will use to update the status of an order and to decide which customers will accept delivery of their vehicle. For accounting and insurance reasons, the order status needs to be updated immediately after a customer accepts their vehicle. To do so, the client application will call a web service to update the order status as soon as the Accepted button is clicked. Our WCF service is interconnected to other parts of our Jupiter Motors application, so we won't see it completely in action until it all comes together. In the meantime, it will seem like we're developing blind. In reality, all the components would probably be developed and tested simultaneously.

Creating a new WCF service web role

When creating a web service, we have a choice to add the web service to an existing web role, or create a new web role. This helps us deploy and maintain our website application separately from our web services. And in order for us to scale the web role independently from the worker role, we'll create our web service in a role separate from our web application. Creating a new WCF service web role is very simple—Visual Studio will do the "hard work" for us and allow us to start coding our services.

First, open the JupiterMotors project. Create the new web role by right-clicking on the Roles folder in our project, choosing Add, and then select the New Web Role Project… option.

Web Services in Microsoft Azure

When we do this, we will be asked what type of web role we want to create. We will choose a WCF Service Web Role, call it JupiterMotorsWCFRole, and click on the Add button. Because different services must have unique names in our project, a good naming convention to use is the project name concatenated with the type of role. This makes the different roles and instances easily discernable, and complies with the unique naming requirement.

Web Services in Microsoft Azure

This is where Visual Studio does its magic. It creates the new role in the cloud project, creates a new web role for our WCF web services, and creates some template code for us. The template service created is called "Service1". You will see both, a Service1.svc file as well as an IService1.vb file. Also, a web.config file (as we would expect to see in any web role) is created in the web role and is already wired up for our Service1 web service. All of the generated code is very helpful if you are learning WCF web services.

This is what we should see once Visual Studio finishes creating the new project:

Web Services in Microsoft Azure

We are going to start afresh with our own services—we can delete Service1.svc and IService1.vb. Also, in the web.config file, the following boilerplate code can be deleted (we'll add our own code as needed):

<system.serviceModel>
<services>
<service name="JupiterMotorsWCFRole.Service1"
behaviorConfiguration="JupiterMotorsWCFRole.
Service1Behavior">
<!-- Service Endpoints -->
<endpoint address="" binding="basicHttpBinding"
contract="JupiterMotorsWCFRole.IService1">
<!--
Upon deployment, the following identity
element should be removed or replaced to reflect the
identity under which the deployed service runs.
If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="JupiterMotorsWCFRole.Service1Behavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the
metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging
purposes, set the value below to true.
Set to false before deployment to avoid
disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

Let's now add a WCF service to the JupiterMotorsWCFRole project. To do so, right-click on the project, then Add, and select the New Item... option.

Web Services in Microsoft Azure

We now choose a WCF service and will name it as ERPService.svc:

Web Services in Microsoft Azure

Just like the generated code when we created the web role, ERPService.svc as well as IERPService.vb files were created for us, and these are now wired into the web.config file. There is some generated code in the ERPService.svc and IERPService.vb files, but we will replace this with our code in the next section. When we create a web service, the actual service class is created with the name we specify. Additionally, an interface class is automatically created. We can specify the name for the class; however, being an interface class, it will always have its name beginning with letter I. This is a special type of interface class, called a service contract. The service contract provides a description of what methods and return types are available in our web service.

Microsoft Azure: Enterprise Application Development Straight talking advice on how to design and build enterprise applications for the cloud using Microsoft Azure with this book and eBook
Published: December 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

Our WCF web services

Our WCF web service is going to expose two functions to return data to the client and one routine to add a message to the queue when an order status is updated on the client.

ERP service interface—IERPService.vb

These following functions and routines will be exposed when the service is called from the client. This is our code in our IERPService.vb file, in the WCFWebService1 role:

Imports System.ServiceModel

' NOTE: If you change the class name "IERPService" here,
you must also update the reference to "IERPService" in Web.config.
<ServiceContract()> _
Public Interface IERPService

<OperationContract()> _
Function LoadStartupData() As DataSet

<OperationContract()> _
Function GetOrderStatusForOrder(ByVal iOrderHeaderID As Integer)
As String

<OperationContract()> _
Sub AddOrderStatusUpdateToQueue(ByVal iOrderHeaderID As
Integer, ByVal iOrderStatusID As Integer)

<DataContract()> _
Class OrderStatus
Private statusName_value As String

<DataMember()> _
Public Property StatusName() As String
Get
Return statusName_value
End Get
Set(ByVal value As String)
statusName_value = value
End Set
End Property

End Class

End Interface

Now that we've created our interface, we can see it looks very similar to a traditional interface, but the class and methods are decorated with contract attributes.

Service Contract

As we mentioned above, a Service Contract is a class-level attribute. The Service Contract is the top level of the service definition, and encapsulates both the operations and data. Just as methods and properties are children of a class, Operation Contracts and Data Contracts are children of a Service Contract.

Operation Contract

The Operation Contract specifies the methods and the method signatures that the web service client can call. Not all methods in the Service Contract need to be labelled as Operation Contracts. Web services may use any number of helper methods to support the publicly accessible ones.

Data Contract

The Data Contract describes how the returned data will be serialized or deserialized. A Data Contract is a separate class in our interface; the data elements are properties with the <DataMember()> attribute.

If we are returning a simple data structure—say a list of names—we do not necessarily need to establish a Data Contract. However, using a Data Contract is recommended as a best practice.

For more advanced data types, even something as basic as a list of name-value pairs, we need to include a Data Contract. We'll use a Data Contract to return the status of an order.

For some additional information on Service, Operation, and Data Contracts, visit http://msdn.microsoft.com/en-us/library/system.servicemodel.servicecontractattribute.aspx. Data Contracts in particular are covered in greater depth at http://msdn.microsoft.com/en-us/library/ms733127.aspx.

Using ADO.NET datasets

As ADO.NET datasets are serializable objects, it is possible to skip using a Data Contract, and allow WCF to serialize a dataset. The one caveat is that we need to make sure our client is .NET based so that it can deserialize the dataset properly. An advantage ADO.NET datasets have is returning multiple recordsets in the same method call. This can speed up performance by reducing the number of server requests. We'll use this technique to load our client application's startup data.

ERP service implementation—ERPService.svc.vb

Here are the actual functions and routines that will be executed when called from the client. We can keep both the functions and routines directly linked to the service calls (these are marked with Implements IERPService.[function or routine name]) and also other functions and routines that can be called (just like any other class):

Imports System.Data.SqlClient
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.StorageClient
Imports Microsoft.WindowsAzure.ServiceRuntime

' NOTE: If you change the class name "ERPService" here,
you must also update the reference to "ERPService" in Web.config
and in the associated .svc file.
Public Class ERPService
Implements IERPService

LoadStartupData service function

This function returns a dataset to the client with two different DataTables—one is the list of orders not yet complete and the other is a list of order statuses. These will be databound to list boxes in the client ERP application.

Private Function LoadStartupData() As DataSet Implements
IERPService.LoadStartupData
Dim _dataSet As New DataSet

_dataSet = GetOrdersNotComplete(_dataSet)
_dataSet = GetOrderStatuses(_dataSet)

Return _dataSet

End Function

GetOrderStatusForOrder service function

This function will accept an Order Header ID and return the status for that particular order. This will be used to show the order status for a selected order, in a list box, in our client ERP application.

Private Function GetOrderStatusForOrder(ByVal iOrderHeaderID As
Integer) As String Implements
IERPService.GetOrderStatusForOrder
Dim _connStr As String =
ConfigurationManager.ConnectionStrings
("portal").ConnectionString
Dim _SQLcon As New SqlConnection(_connStr)
Dim _SQLcmd As New SqlCommand()

_SQLcon.Open()

With _SQLcmd
.CommandText = "GetOrderStatusForOrderHeaderID"
.CommandType = CommandType.StoredProcedure
.Connection = _SQLcon
.Parameters.AddWithValue
("@orderHeaderID", iOrderHeaderID)
End With

Return _SQLcmd.ExecuteScalar().ToString

End Function

AddOrderStatusUpdateToQueue service function

The following function will take the Order Header ID for a selected order, the Order Status ID for a selected status, and add a message to our queue for our worker role to pick up and update the order

Private Sub AddOrderStatusUpdateToQueue(ByVal iOrderHeaderID As
Integer, ByVal iOrderStatusID As Integer)
Implements IERPService.AddOrderStatusUpdateToQueue
Dim _account =
CloudStorageAccount.DevelopmentStorageAccount()
Dim _client = _account.CreateCloudQueueClient()
Dim _queue As CloudQueue =
_client.GetQueueReference("orderupdatequeue"

_queue.CreateIfNotExist()

Dim _msg As New CloudQueueMessage
(iOrderHeaderID & "," & iOrderStatusID)
_queue.AddMessage(_msg)
End Sub

GetOrdersNotComplete, GetOrderStatuses, and CreateDataSetFromDataReader class functions

The following functions will do the work of retrieving data and packaging the DataTables into the DataSet to return to the client. These functions will be called by the service functions we looked at in the previous section. They do not implement a service function.

Private Function GetOrdersNotComplete
(ByVal dsLoadData As DataSet) As DataSet
Dim _connStr As String =
ConfigurationManager.ConnectionStrings
("portal").ConnectionString
Dim _SQLcon As New SqlConnection(_connStr)
Dim _SQLcmd As New SqlCommand()

_SQLcon.Open()

With _SQLcmd
.CommandText = "GetOrdersNotComplete"
.CommandType = CommandType.StoredProcedure
.Connection = _SQLcon
End With

dsLoadData = CreateDataSetFromDataReader
(_SQLcmd.ExecuteReader(),
dsLoadData, "OrdersNotComplete")
Return dsLoadData
End Function

Private Function GetOrderStatuses
(ByVal dsLoadData As DataSet) As DataSet
Dim _connStr As String =
ConfigurationManager.ConnectionStrings
("portal").ConnectionString
Dim _SQLcon As New SqlConnection(_connStr)
Dim _SQLcmd As New SqlCommand()

_SQLcon.Open()

With _SQLcmd
.CommandText = "GetOrderStatuses"
.CommandType = CommandType.StoredProcedure
.Connection = _SQLcon
End With

dsLoadData = CreateDataSetFromDataReader
(_SQLcmd.ExecuteReader(),
dsLoadData, "OrderStatuses")
Return dsLoadData
End Function

Private Function CreateDataSetFromDataReader
(ByVal drReader As SqlDataReader,
ByVal dsDataSet As DataSet, ByVal
sTableName As String) As DataSet
Do
Dim _schemaTable As DataTable = drReader.GetSchemaTable()
Dim _dataTable As New DataTable()

If _schemaTable IsNot Nothing Then
'The SqlDataReader returned results
'Set the DataTable Name to reference from DataSet
_dataTable.TableName = sTableName

For i As Integer = 0 To _schemaTable.Rows.Count - 1
Dim _dataRow As DataRow = _schemaTable.Rows(i)
'Create the column names
Dim _columnName As String =
_dataRow("ColumnName").ToString
'Set the column type
Dim _column As New DataColumn
(_columnName, DirectCast
(_dataRow("DataType"), Type))
_dataTable.Columns.Add(_column)
Next

'Add DataTable to DataSet
dsDataSet.Tables.Add(_dataTable)

'Fill DataTable with results from SqlDataReader
While drReader.Read()
Dim _dataRow As DataRow = _dataTable.NewRow()

For i As Integer = 0 To drReader.FieldCount - 1
_dataRow(i) = drReader.GetValue(i)
Next

_dataTable.Rows.Add(_dataRow)
End While
End If
Loop While drReader.NextResult()
Return dsDataSet
End Function
End Class

DataTable "gotcha"

Our original plan was to make two different calls to the web service for the databinding of the list boxes, and passing back the lists as a DataTable to the client. The beauty of WCF services is that they can accept and return a wide variety of serializable objects. At the time of writing, DataTables have been made serializable but are not yet working through WCF, though DataSets are. This is why we opted to package the DataTables into a DataSet and pass it back to the client.

There are advantages and disadvantages to doing it this way. There are two major advantages to this:

  • We need to give only one call to the client with only one returned object to use
  • Client application speed is greater with only one call

The disadvantage to this is that the total size of a DataSet with one DataTable is much bigger than the size of just the DataTable itself. The increased size could take longer to transfer and also use more bandwidth. Our example is a very small set of data; however, the DataSets in a real-life enterprise application could be a lot bigger.

Web Service Definition Language (WSDL) "gotcha"

The Windows Azure development fabric runs on localhost, port 81 (or http://localhost:81 as you would see it in your Internet browser). If you've ever dealt with web services, the following information displayed on the page in your internet browser will look familiar:

Great news! Our service seems to be running fine! Or is it? Look at the link for the service to get the WSDL: http://localhost:1289/ERPService.svc?wsdl That's not the port we were expecting. If you follow the instructions on the page to test it using the svcutil.exe, we get the following error:

Error: Cannot obtain Metadata from http://localhost:1289/ERPService.svc. If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error URI: http://localhost:1289/ERPService.svc Metadata contains a reference that cannot be resolved: http://localhost:1289/ERPService.svc. There was no endpoint listening at http://localhost:1289/ERPService.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. The remote server returned an error: (400) Bad Request.HTTP GET Error URI: http://localhost:1289/ERPService.svc There was an error downloading http://localhost:1289/ERPService.svc. The request failed with HTTP status 400: Bad Request.

It looks like there is a metadata error, but we know we have metadata publishing enabled as the page is able to display the publishing instructions. After digging around for the answer, the problem was found. The schemaLocation reference was incorrect in the WSDL. Microsoft has released a hotfix to correct this (one for Vista and Server 2008, and the other for Windows 7):

Once downloaded and installed, the address to get the WSDL stays the same; however, the schemaLocation reference is corrected and all is fine once again! Now that we're able to generate the WSDL in our local development environment, we're set to develop our client application.

Summary

In this article, we looked briefly at web services and WCF, and how they fit into an Azure project. We then developed our WCF classes in a new web role. Because our web service is interconnected to other parts of the Jupiter Motors portal project, there is additional work to be done before we can see the web services in action. Web services are very powerful, and we're only scratching the surface, so if additional samples are desired, a good resource is available at http://code.msdn.microsoft.com/wcfazure.

Microsoft Azure: Enterprise Application Development Straight talking advice on how to design and build enterprise applications for the cloud using Microsoft Azure with this book and eBook
Published: December 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Nathan A. Duchene

Nathan Duchene is an Application Developer for Armada Supply Chain Solutions, a logistics company based in Pittsburgh, PA. He has worked with a list of Microsoft technologies, including ASP.NET, Silverlight, SharePoint, BizTalk, and SQL Server. Nathan also enjoys playing numerous sports, volunteering in the community, and spending time with his family and closest friends in his spare time.

Richard J. Dudley

Richard Dudley is a Senior Application Developer for Armada Supply Chain Solutions, a logistics company based in Pittsburgh, PA. Richard has been developing with Microsoft technologies since 1998, and today works with a variety of technologies, including SQL Server, ASP.NET, SharePoint and BizTalk. With his wife Kathy, Richard is also co-owner of The Bloomery Florist in Butler, PA

Books From Packt


Microsoft Dynamics NAV 2009 Application Design
Microsoft Dynamics NAV 2009 Application Design

Microsoft Silverlight 4 Data and Services Cookbook
Microsoft Silverlight 4 Data and Services Cookbook

Microsoft Dynamics GP 2010 Implementation
Microsoft Dynamics GP 2010 Implementation

Microsoft Dynamics NAV Administration
Microsoft Dynamics NAV Administration

Applied Architecture Patterns on the Microsoft Platform
Applied Architecture Patterns on the Microsoft Platform

Getting Started with Oracle BPM Suite 11gR1 – A Hands-On Tutorial
Getting Started with Oracle BPM Suite 11gR1 – A Hands-On Tutorial

IBM Cognos 8 Report Studio Cookbook
IBM Cognos 8 Report Studio Cookbook

PostgreSQL 9.0 High Performance
PostgreSQL 9.0 High Performance


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
D
j
q
r
h
5
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software