To handle SOAP requests in an SOI, you must implement I
and I
. These interfaces contain two methods, Handle
and Handle
, which allow you to intercept SOAP requests and execute your own business logic.
The Handle
method handles all the SOAP binary requests that come from ArcObjects-based clients, such as ArcMap, ArcGIS Engine, or custom ArcObjects applications. For example, accessing and rendering a map service on ArcMap makes the requests come through the Handle
method.
The Handle
method handles all the SOAP XML string requests that come from non-ArcObjects-based clients, such as requests made via SOAP SDK.
To preprocess the SOAP request, you must unpack the incoming request, customize the request parameters, repack the request, and send it to the underlying service object for processing. Similar procedure also applies to postprocessing responses. To postprocess the SOAP response, you must unpack the response, customize the response content, repack the response to appropriate format, and send it back to the client. The SDK contains utility classes to assist with packing and unpacking the relevant request and response objects.
This topic demonstrates the workflows for handling SOAP binary requests using the Handle
method and SOAP string requests using the Handle
method.
Use the Handle Binary Request2()
method
The following code in the Handle
method is automatically generated if you create an SOI from the Visual Studio template.
public byte[] HandleBinaryRequest2(string Capabilities, ref byte[] request)
{
_serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleBinaryRequest2()",
200, "Request received in Sample Object Interceptor for HandleBinaryRequest2");
IRequestHandler2 requestHandler = _restSOIHelper.FindRequestHandlerDelegate<IRequestHandler2>();
if (requestHandler != null)
{
return requestHandler.HandleBinaryRequest2(Capabilities, request);
}
return null;
}
Once a SOAP binary request is received, the above Handle
function will be triggered, and its Capabilities
and request
variables will be populated with the request information, such as request name and request parameters. Based on these variables, the I
method will generate the response, which is also a byte array.
The following code snippet demonstrates how to preprocess a SOAP binary request. It keeps only the first layer visible for the export operation of a map service, no matter how many layers exist in the map service.
To achieve this function, you must find the parameter that controls the layer visibility for the export operation. Based on SOAP SDK, the SOAP method for the export operation is ExportMapImage, whose input parameter Map
defines the content of the map to be exported. One of Map
's properties is Layer
, which is an array of Layer
with the I
property to control the layer visibility. In this way, you can track down the objects to customize in the SOI.
Sample code:
public byte[] HandleBinaryRequest2(string Capabilities, ref byte[] request)
{
IRequestHandler2 requestHandler = _restSOIHelper.FindRequestHandlerDelegate<IRequestHandler2>();
if (requestHandler != null)
{
IMessage requestMessage = SoapSOIHelper.ConvertBinaryRequestToMessage(request);
string requestName = requestMessage.Name;
_serverLog.LogMessage(ServerLogger.msgType.infoSimple, _soiName + ".RequestName", 200, "Request Name: " + requestName);//For more information about server logs, go to topic: how to audit requests in SOIs
if (requestName == "ExportMapImage")
{
IXMLSerializeData requestParams = requestMessage.Parameters;
int mapdescriptIndex = requestParams.Find("MapDescription");
IMapDescription mapDescription = requestParams.GetObject(mapdescriptIndex, requestMessage.NamespaceURI, "MapDescription") as IMapDescription;
int layerCount = mapDescription.LayerDescriptions.Count;
for (int i = layerCount - 1; i > 0; i--)
{
mapDescription.LayerDescriptions.Element[i].Visible = false;//Keep only the first layer visible in export operation
}
byte[] modifiedRequest = SoapSOIHelper.ConvertMessageToBinaryRequest(requestMessage);
return requestHandler.HandleBinaryRequest2(Capabilities, modifiedRequest);
}
return requestHandler.HandleBinaryRequest2(Capabilities, request);
}
//Insert error response here.
return null;
}
The above code first calls the Soap
method to convert the byte-array request to I
, which provides access to the request name string and request parameters as IXML
. Second, the IXML
method is called to retrieve I
, which is the input parameter to customize in this workflow. Then, I
can be returned from the I
array and I
property can be set. Last, the Soap
method converts the modified request back to byte-array format. This modified byte-array request can then be passed to I
for the service object to process and generate the corresponding response based on the modified request.
Postprocessing SOAP binary responses works in a similar way. First, you must obtain the byte-array response returned from the I
method with either the original or modified request. Next, you will convert the byte-array response to I
using the Soap
method. The I
interface provides access to the response content via I
, which returns an object that can be cast to the IXML
interface. Calling the IXML
method will return the Result
object. The Result
object can be cast to the corresponding interface or class which provides access to the element for modification. After the response element is modified, you must convert it from I
to a byte array by using Soap
and return the byte-array response to the client.
To test the above code, you can deploy the SOI and enable the SOI with a map service. After you add the map service to ArcMap, only the first layer should display on the map. As this code only modifies ExportMapImage, to customize other SOAP methods, such as GetLegendInfo, you can refer to the .NET layer access SOI sample.
Use the Handle String Request()
method
The following code in the Handle
method is automatically generated if you create an SOI from the Visual Studio template.
public string HandleStringRequest(string Capabilities, string request)
{
_serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleStringRequest()",
200, "Request received in Sample Object Interceptor for HandleStringRequest");
IRequestHandler requestHandler = _restSOIHelper.FindRequestHandlerDelegate<IRequestHandler>();
if (requestHandler != null)
{
return requestHandler.HandleStringRequest(Capabilities, request);
}
//Insert error response here.
return null;
}
Unlike the Handle
method, Handle
intercepts all the SOAP requests that come from non-ArcObjects-based clients, such as XML requests sent to the service SOAP endpoint from custom applications using SOAP SDK.
When the request reaches the service SOAP endpoint, the Handle
method is triggered and the requests are directly passed in as the request
string variable. Based on the request
and capabilities
variables, I
generates the response, which is also an XML string.
To preprocess the SOAP string request, you will first convert the request string to I
. Then, the request parameters can be accessed from the I
method and cast to IXML
, whose Get
method can be used to retrieve the underlying request object for modification. After the request object is modified, you must call the Soap
method to copy a new I
from the original one, and use the Soap
method to commit the changes of the request object to the copied I
, which can then be converted back to a string via Soap
. This string can be passed to I
for the service object to process and generate a response.
The same logic also applies to postprocessing SOAP string responses. In the following sample code, the SOI adds a custom message to the Comments
property of the map service’s GetDocumentInfo response.
To customize this response, you must understand the response object type first. Based on SOAP SDK, the GetDocumentInfo method returns a Property
which contains a Property
named Comments
. This Property
can be accessed via I
in Enterprise SDK and its value can be set by the I
method. Note that the modified Property
must be committed to I
copied from the Soap
method.
Sample code:
public string HandleStringRequest(string Capabilities, string request)
{
_serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleStringRequest()", 200, "Capabilities: " + Capabilities);
_serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleStringRequest()", 200, "Request received: " + request);
IRequestHandler requestHandler = _restSOIHelper.FindRequestHandlerDelegate<IRequestHandler>();
if (requestHandler != null)
{
string response = requestHandler.HandleStringRequest(Capabilities, request);
IMessage responseMessage = SoapSOIHelper.ConvertStringRequestToMessage(response);
if (responseMessage.Name == "GetDocumentInfoResponse")
{
int resultIndex = responseMessage.Parameters.Find("Result");
IPropertySet propSet = responseMessage.Parameters.GetObject(resultIndex, responseMessage.NamespaceURI, "PropertySet")
as IPropertySet;
propSet.SetProperty("Comments", "Custom message from SOI.");
//_SoapSOIHelper is instantiated at SOE's Init() method:
//_SoapSOIHelper = new SoapSOIHelper(pSOH,
// "C:\\Program Files\\ArcGIS\\Server\\framework\\runtime\\ArcGIS\\Resources\\XmlSchema\\MapServer.wsdl");
IMessage modifiedResponseMsg = _SoapSOIHelper.CreateNewIMessage(responseMessage);
IXMLSerializeData modifiedData = modifiedResponseMsg.Parameters;
_SoapSOIHelper.AddObjectToXMLSerializeData("Result", propSet, "PropertySet", modifiedData);
string modifiedResponse = SoapSOIHelper.ConvertMessageToStringRequest(modifiedResponseMsg);
return modifiedResponse;
}
_serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleStringRequest()", 200, "Response: " + response);
return response;
}
//Insert error response here.
return null;
}
In the above code, the request
variable is directly passed to the I
method to generate the raw response string. Then, by calling Soap
, the raw response string is converted to I
, which provides access to the response name and the response content as IXML
.
As this code intercepts the response from the GetDocumentInfo method, the name of the response should be GetDocumentInfoResponse. Typically, the name of the response is the service’s SOAP method name with Response
appended, and the name of the SOAP response content is Result
. In this case, the Result
object is of type Property
(see GetDocumentInfo). You can set the value of the Comments
property by using I
.
Next, you must call the Soap
method to copy a new response I
from the original I
. This will allow the updated response element I
to be committed to the new I
via the the Soap
method.
Finally, you can convert the modified response I
to a string through the Soap
method. This modified string response will be returned in the Handle
method and sent to the client.
To test how the above code works in the SOI, you can deploy the SOI and enable the SOI with a map service. You can use any non-ArcObjects-based SOAP client to send a GetDocumentInfo request, and you will find the value of the Comments
property in the response XML shows the custom message defined in the SOI.