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
IERPService.vb file, WCF web serviceabout' 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.
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
ERPService.svc.vb, WCF web serviceaboutImports 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.
Private Function LoadStartupData() As DataSet Implements IERPService.LoadStartupData
service functionLoadStartUpDataDim _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
ERPService.svc.vb, WCF web serviceGetOrderStatusForOrder service function.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()
class functionsGetOrderStatusesWith _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
ERPService.svc.vb, WCF web serviceGetOrderStatuses functionDo
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