S A M P L E S
C# code examples for working with Proxy classes
This page contains C# code examples for working with ArcGIS Server SOAP
proxy classes. By default, the name for the SOAP
proxy class is the name of the service used to generate it plus the service
type. For
example, if a SOAP proxy class is generated dynamically using a map service
named "NorthAmerica", the proxy class name will be "NorthAmerica_MapServer". For
the purposes of the example code, the proxy class names will be <service
name>_<service type>.
The following techniques
for working with proxy classes are discussed:
Providing HTTP\Windows authentication credentials
Using token-based authentication
Modifying HTTP request properties
Converting between SOAP value object types with different namespaces
Providing
HTTP\Windows authentication credentials
In general, clients that make Internet connections to ArcGIS Server services use a Web service proxy (generated by a WSDL). The proxy works with the Web service via SOAP over HTTP. The client does not need to impersonate to work with ArcGIS Server services via an Internet connection. Note that impersonation is merely the ability to control the identity under which client code is executed. Instead, the client process can provide authentication information via the HTTP protocol to the Web server\application. To provide authentication information using a Web service proxy, set the credentials on the proxy. Using .NET, you can create a new NetworkCredential, provide the user, password, and domain and assign it to the Web service proxy via the Credentials property before calling any methods on the proxy. The example below illustrates how to check whether authentication is enabled on a Web service, and if so, provide credential information.
MapService_MapServer mapservice = new MapService_MapServer();
mapservice.Url = "http://localhost/arcgis/services/MapService/MapServer";
string url_401 = mapservice.Url + "?wsdl";
HttpWebRequest webRequest_401 = null;
webRequest_401 = (HttpWebRequest)HttpWebRequest.Create(url_401);
webRequest_401.ContentType = "text/xml;charset=\"utf-8\"";
webRequest_401.Method = "GET";
webRequest_401.Accept = "text/xml";
HttpWebResponse webResponse_401 = null;
while (webResponse_401 == null || webResponse_401.StatusCode != HttpStatusCode.OK)
{
try
{
webResponse_401 = (HttpWebResponse)webRequest_401.GetResponse();
}
catch (System.Net.WebException webex)
{
HttpWebResponse webexResponse = (HttpWebResponse)webex.Response;
if (webexResponse.StatusCode == HttpStatusCode.Unauthorized)
{
if (webRequest_401.Credentials == null)
{
webRequest_401 = (HttpWebRequest)HttpWebRequest.Create(url_401);
webRequest_401.ContentType = "text/xml;charset=\"utf-8\"";
webRequest_401.Method = "GET";
webRequest_401.Accept = "text/xml";
webRequest_401.Credentials = new NetworkCredential("user","password");
}
else
{
// if original credentials not accepted, return
return;
}
} else {
// if web service unavailable, StatusCode = NotFound, return
return;
}
} catch (Exception ex) { }
}
if (webResponse_401 != null)
webResponse_401.Close();
if (webRequest_401.Credentials != null)
mapservice.Credentials = webRequest_401.Credentials;
// If proper credentials provided, default map name should be returned
string mapname = mapservice.GetDefaultMapName();
Using token-based authentication
To determine whether the server accepts or requires tokens, you can use the RequiresTokens method of the Catalog. If RequiresTokens is true, you can then obtain the URL of the token service with the GetTokenServiceURL() method.
Catalog myCatalog = new Catalog();
myCatalog.Url = "http://localhost/arcgis/services";
if (myCatalog.RequiresTokens())
{
string tokenServiceUrl = myCatalog.GetTokenServiceURL();
}
Of course, you may already know the URL of the token service from the server's administrator. The token service is at a URL such as "http://localhost/arcgis/tokens". Once you know the token service URL, you can request a token, assuming you have a valid user name and password for the ArcGIS Server instance. You can use the WebRequest class to make a request for the token. Note that the request may encounter problems such as an unresponsive server, incorrect password, etc. You should wrap the request in a try-catch block to deal with errors.
string url = tokenServiceUrl + "?request=getToken&username=myuser&password=secret";
System.Net.WebRequest request = new System.Net.WebRequest.Create(url);
System.Net.WebResponse response = request.GetResponse();
System.IO.Stream responseStream = response.GetResponseStream();
System.IO.StreamReader readStream = new System.IO.StreamReader(responseStream);
string myToken = readStream.ReadToEnd();
The token will be a long string of characters. It must be appended to the URL of the web service endpoint with each request. You do not need to include it within the request itself. The example above for the map server would be modified to include the token:
MapService_MapServer mapservice = new MapService_MapServer();
mapservice.Url = "http://localhost/arcgis/services/MapService/MapServer?token=" + myToken;
Tokens expire within a
time period designated by the server administrator. The expiration timeout
window may vary from a few minutes to several days. Currently there is
no programmatic method to ascertain the token timeout. Therefore you must
account for token expiration in your code, and obtain a new token when
required.
Currently the way to detect timeout of a token is to catch the exception thrown and to check the response code. A code of 498 indicates an expired or otherwise invalid token. A code of 499 indicates that a token is required (if no token was submitted). Once you determine that a new token is needed, you can request one, update the server's URL with the token, and repeat the request.
MapImage mapimg = null;
try {
mapimg = mapservice.ExportMapImage(mapdesc, imgdesc);
}
catch (System.Net.WebException webExc) {
System.Net.HttpWebResponse webResp = webExc.Response as System.Net.HttpWebResponse;
if (webResp != null) {
int statusCode = (int)webResp.StatusCode;
if (statusCode == 498) {
// call a method (not shown here) that obtains a new token
string newToken = getToken();
mapservice.Url = "http://MyWebServer/arcgis/services/MapService/MapServer?token=" + newToken;
mapimg = mapservice.ExportMapImage(mapdesc, imgdesc);
}
}
}
Modifying
HTTP request properties
Change Web request properties by subclassing the ArcGIS Server Web Service
proxy class and overriding the GetWebRequest method. This
will give you access to the .NET HttpWebRequest class on which you can
change properties such as KeepAlive and ProtocolVersion. The
following example illustrates how to change the aforementioned properties:
public class ExtendedMyMapServiceProxy : MyMapServiceProxy
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest =
(System.Net.HttpWebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
webRequest.ProtocolVersion = System.Net.HttpVersion.Version10;
return webRequest;
}
}
Converting
between SOAP value object types with different namespaces
Since SOAP value objects are defined within a WSDL, the same value object
types can be generated in different namespaces. SOAP
proxies and value objects must have the same namespace to be used together.
This often presents a problem when devising
solutions that use dynamic ArcGIS Server value objects you have generated
and ArcGIS Server value objects in another product for which you cannot
change the namespace. For example, assume
you generate a set of dynamic value objects with the namespace "wsmap".
If you create a wsmap.Envelope and attempt
to use it with an ESRI.ArcGIS.ADF.ArcGISServer.SpatialFilter by assigning
it to the FilterGeometry property, a compile time error will occur. In
general, the types are different because the namespaces are different.
If you have complete control over the generation
of SOAP proxies and value objects, you can generate value object types
that can be shared across ArcGIS Server service types (e.g. PolygonN is
included with every ArcGIS Server service type). If
you are unable to modify the namespace for SOAP proxies and value objects,
you can use the following code to convert between namespaces. In
the example, a PolylineN created dynamically is being converted to an
ESRI.ArcGIS.ADF.ArcGISServer.PolylineN. The
.NET System.Xml.Serialization.XmlSerializer is used to serialize and deserialize
the SOAP value object to and from a string.
// Serialize value object into SOAP string
Type valueType = dynamicSoapPolylineN.GetType();
System.Xml.Serialization.XmlSerializer xmlSerializer =
new
System.Xml.Serialization.XmlSerializer(valueType);
System.Text.StringBuilder stringBuilder = new StringBuilder();
System.IO.StringWriter stringWriter = new System.IO.StringWriter(stringBuilder);
xmlSerializer.Serialize(stringWriter, dynamicSoapPolylineN);
string soapSerializedValueObject = stringBuilder.ToString();
// Read SOAP string to deserialize to same type, different namespace
System.Xml.XmlTextReader xmlTextReader =
new System.Xml.XmlTextReader(new System.IO.StringReader(soapSerializedValueObject));
System.Xml.Serialization.XmlSerializer mySerializer = new
System.Xml.Serialization.XmlSerializer
(typeof(ESRI.ArcGIS.ADF.ArcGISServer.PolylineN));
object newValueObject = mySerializer.Deserialize(xmlTextReader);
ESRI.ArcGIS.ADF.ArcGISServer.PolylineN adfSoapPolylineN =
(ESRI.ArcGIS.ADF.ArcGISServer.PolylineN)newValueObject;