On the server side, the XIR ASP page receives the client's post
request. This page simply calls ProcessRequest on the XIR server,
which is responsible for all the rest. The XIR server is an MTS/COM+
component designed to be called only from ASP. It retrieves the
posted XML string by getting the ASP Request object using
GetObjectContext("Request"). Similarly, it writes the response XML
string directly to the ASP Response object.
ProcessRequest starts by creating a response document as shown in
figure 8. It then goes through each servicecall in the request
document and processes that call adding any output to the response
document. This is necessary because XIR allows the client to batch up
several service calls into one request. To process a service call,
the server creates a new, empty XML element representing the
servicereturn value. It then calls GetServiceInfo using the service
id to lookup the component's progid, method name, call type and
return value type -if any. This lookup is performed against the
service catalog discussed earlier. Be sure to point this function to
the correct path of your services catalog document. Each of the
service parameters is then re-hydrated from XML to the appropriate
data type using XML2Vnt and placed in an array. Parameters are placed
in this array in reverse order since this is how they are needed by
XIRCBN. After all parameters have been re-hydrated, XIRCBN is used to
make the actual call and get the return value-if any. This return
value is then converted to XML using Vnt2XML and added to the
servicereturn as its text property. Finally, the servicereturn
element is appended as a child to the response document.
Figure 8 XIR Server's ProcessRequest
Public Sub ProcessRequest()
'declarations ommitted for clarity
On Error GoTo eh
'create a new XML document and
'load it from the ASP Request object
Set oRequest = New DOMDocument
oRequest.async = False
oRequest.Load GetObjectContext("Request")
Set oResponse = New DOMDocument
'start writing out response
oResponse.loadXML "<?xml
version='1.0'?><XIRResponse></XIRResponse>"
'get list of calls in request document
Set oCalls = oRequest.getElementsByTagName("servicecall")
'create it here and reuse it later
Set oXIRCBN = CreateObject("XIRCBN.Caller")
For Each oCall In oCalls
'lookup service info
sServiceId = oCall.getAttribute("serviceid")
Call GetServiceInfo(sServiceId, sProgID, _
sMethodName, eCallType, eRetValType)
Set oServiceReturn = oResponse.createElement( _
"servicereturn")
oServiceReturn.setAttribute "callid", _
oCall.getAttribute("callid")
'Get number of parameters
Set oParams = oCall.getElementsByTagName("param")
If
(Not oParams Is Nothing) And (oParams.length > 0) Then
iNumParams = oParams.length
'Create a variant array with number of params
ReDim vaParams(iNumParams - 1)
'For each param, check its type
'Put variant in array in reverse order!
iParamIndex = iNumParams - 1
For Each oParam In oParams
eParamType = GetServiceParamType(sServiceId, _
iNumParams - iParamIndex - 1)
XML2Vnt oParam.Text, eParamType,_
vaParams(iParamIndex)
iParamIndex = iParamIndex - 1
Next 'oParam
End If
'Make call
If
mocx Is Nothing Then
Set oServer = CreateObject(sProgID)
Else
Set oServer = mocx.CreateInstance(sProgID)
End If
'how we call it depends on the type of call
If
eRetValType = vbEmpty Then
'Making call and expecting no return value
oXIRCBN.MakeCall oServer, sMethodName, _
eCallType, vaParams
Else
If
eRetValType = vbObject Then
'Making call and expecting object
Set vntRetVal = oXIRCBN.MakeCall(oServer, _
sMethodName, eCallType, vaParams)
Else
'Making call and expecting simple return type
vntRetVal = oXIRCBN.MakeCall(oServer, _
sMethodName, eCallType, vaParams)
End If
'send retval to XML
oServiceReturn.setAttribute "returnType", eRetValType
oServiceReturn.Text = Vnt2XML(vntRetVal)
End If
'add to response document
oResponse.documentElement.appendChild oServiceReturn
Next 'oCall
'Send response back out
Set oASPResponse = GetObjectContext("Response")
oASPResponse.ContentType = "text/xml"
oASPResponse.Write oResponse.xml
Exit Sub
eh:
App.LogEvent Err.Description
End Sub
After all service calls have been processed, the response
document's XML is written out to the ASP Response object and is
returned to the client as the HTTP response. The client then extracts
the servicereturn elements from this response and re-hydrates the
actual variants using XML2Variant.
Name Calling
All the XIR components I discussed so far are implemented using
VB. However, the XIRCBN component had to be implemented using ATL. As
I mentioned earlier, the XIR server uses the XIRCBN component to make
component calls given the method name at runtime. Although VB offers
a CallByName function, it assumes you know the number of parameters
at design time. Clearly, this would not work for the XIR server, in
fact there are very few applications when you don't know a method
name at design time but you know the number of parameters it takes.
To overcome this limitation, I wrote a simple ATL component that
accepts an object, a method name and an array of parameters. It then
calls the specified method on the supplied object passing it the
parameter array. It does this using IDispatch::Invoke, which lets you
call a method using its dispid and an array of parameters in reverse
order. That is why ProcessRequest places request parameters in an
array in reverse order as discussed above.
XIRCBN is simple yet powerful component that may be used outside
of the XIR. You can use it in your applications whenever you need to
call a method without knowing its name and complete signature at
design time.