5.3. Preparing Your Development EnvironmentNow that you know how to get started with MapPoint Web Service, let's look at how to prepare your development environment to develop MapPoint Web Service applications. 5.3.1. Adding a Web Reference
If you are developing managed code applications using Visual Studio .NET 2003 or later, programming with MapPoint Web Service is
Figure 5-3. Add Web Reference context menu
When you see the Add Web Reference dialog window, type the MapPoint Web Service staging service URL in the URL textbox, as shown in Figure 5-4. Once you type the staging service URL, and the WSDL document is parsed by Visual Studio, the documentation available within the WSDL document is shown in the preview pane. At this point, you can click the Add Reference button to add the MapPoint Web Service as a web reference to your project. When you click on the Add Reference button, Visual Studio .NET automatically creates a proxy class that can be used to program with MapPoint Web Service. By default, this proxy class is named Reference.cs (or Reference.vb ) and is placed within the Web References directory created inside the project's root directory (this file can only be seen when the Show All Files mode is enabled in the Visual Studio .NET solution explorer). The location of the Reference.cs file is shown in Figure 5-5. Figure 5-4. Adding MapPoint Web Service staging service as a web reference
This class file contains all the C# (or VB.NET) equivalents of the interface definitions in the WSDL document. For example, the MapPoint Web Service WSDL document contains a complex type to represent latitude and longitude:
<s:complexType name="LatLong">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" default="0" name="Latitude" type="s:double" />
<s:element minOccurs="0" maxOccurs="1" default="0" name="Longitude" type="s:double" />
</s:sequence>
</s:complexType>
Figure 5-5. Proxy class file added by Visual Studio .NET
This type definition is represented as a class in the Reference.cs file:
public class LatLong {
/// <remarks/>
[System.ComponentModel.DefaultValueAttribute(0)]
public System.Double Latitude = 0;
/// <remarks/>
[System.ComponentModel.DefaultValueAttribute(0)]
public System.Double Longitude = 0;
}
As you can see, the previous class is a pure programmatic type representation of the XSD type defined in the WSDL document. You can use this type in your applications as you can any other .NET type. Not all the classes in the proxy file (
Reference.cs
or
Reference.vb
) are pure type definitions with just structure information like LatLong class; there are also some classes with
If you are not familiar with service URLs , they are the so-called "service endpoints " of a web service that offer remote methods that can be invoked in a distributed environment. For MapPoint Web Service, there are four service endpoints that map to the service class types specified previously. The service URL and service class type mapping are shown in Table 5-1. Table 5-1. MapPoint web service endpoints
Each one of the above four types (classes) has a constructor with the service URL hardcoded in the constructor; for example, if you look for the constructor of the
FindServiceSoap
class in the
Reference.cs
file, you will find the definition as
public FindServiceSoap()
{
this.Url = "http://findv3.staging.mappoint.net/Find-30/FindService.asmx";
}
When you invoke any methods on the FindServiceSoap class, a proxy class for the Find Service, you are remotely invoking methods on the MapPoint Web Service servers. However, if you look closely, the previously stated service URL is pointing to the MapPoint Web Service staging servers. When you want your application to work with the MapPoint Web Service production servers, you must change the URL to point to the production WSDL and recompile the application, which can be an issue if you want to switch between the staging and production environments without re-compiling the application each time you switch. However, it has a very simple workaroundjust make the service URL configurable. 5.3.1.1. Static versus dynamic service URLAfter adding a web reference using Visual Studio .NET, you can choose whether to make the service URL dynamic, meaning that the proxy classes are generated such that the service URLs can be configured and managed via the config file ( web.config for web applications and app.config for Windows applications). The default option is a static service URL. Figure 5-6 shows the web reference property to change the URL's behavior. If you look at the FindServiceSoap constructor with the dynamic service URL option, the class constructor looks as follows:
public FindServiceSoap()
{
string urlSetting =
System.Configuration.ConfigurationSettings.AppSettings["myapp.CommonService"];
if ((urlSetting != null))
{
Figure 5-6. URL behavior setting
this.Url = string.Concat(urlSetting, "FindService.asmx");
}
else
{
this.Url = "http://findv3.staging.mappoint.net/Find-30/FindService.asmx";
}
}
The constructor first
<appSettings>
<add key="myapp.CommonService"
value="http://findv3.
staging
.mappoint.net/Find-30/"/>
</appSettings>
</configuration>
Along similar lines, add the following value to access the production MapPoint Web Service:
<appSettings>
<add key="myapp.CommonService"
value="http://findv3.
service
.mappoint.net/Find-30/"/>
</appSettings>
</configuration>
To enable dynamic service URL behavior, in an ideal world, you would select the Dynamic option for the URL Behavior property from Visual Studio .NET, and you would be all setexcept that you aren't. The dynamic URL feature in Visual Studio .NET does not work for MapPoint Web Service. In Visual Studio .NET, the static/dynamic service URL feature was designed for web services with one service endpoint per WSDL document, which means there is only class that implements SoapHttpClientProtocol type per Reference.cs or Reference.vb file. Even if there is more than one service endpoint, the assumption was that the base URL of the service is always the same; however, for MapPoint Web Service, one WSDL actually points to four services that have three physical service endpoints . So, in order to make your MapPoint Web Service proxy class properly enabled with dynamic URL behavior, you need to do the following steps: First, add the following key to your configuration file:
<appSettings>
<add key="myapp.CommonService"
value="http://findv3.staging.mappoint.net/Find-30/Common.asmx"/>
<add key="myapp.FindService"
value="http://findv3.staging.mappoint.net/Find-30/Find.asmx"/>
<add key="myapp.RouteService"
value="http://routev3.staging.mappoint.net/Route-30/Route.asmx"/>
<add key="myapp.RenderService"
value="http://renderv3.staging.mappoint.net/Render-30/Render.asmx"/>
</appSettings>
CommonServiceSoap class:
public CommonServiceSoap() {
string urlSetting =
System.Configuration.ConfigurationSettings.AppSettings["myapp.CommonService"];
if ((urlSetting != null)) {
this.Url = urlSetting;
}
else {
this.Url = "http://findv3.staging.mappoint.net/Find-30/CommonService.asmx";
}
}
FindServiceSoap class:
public FindServiceSoap() {
string urlSetting =
System.Configuration.ConfigurationSettings.AppSettings["myapp.FindService"];
if ((urlSetting != null)) {
this.Url = urlSetting;
}
else {
this.Url = "http://findv3.staging.mappoint.net/Find-30/FindService.asmx";
}
}
RouteServiceSoap class:
public RouteServiceSoap() {
string urlSetting =
System.Configuration.ConfigurationSettings.AppSettings["myapp.RouteService"];
if ((urlSetting != null)) {
this.Url = urlSetting;
}
else {
this.Url = "http://routev3.staging.mappoint.net/route-30/RouteService.asmx";
}
}
RenderServiceSoap class:
public RenderServiceSoap() {
string urlSetting =
System.Configuration.ConfigurationSettings.AppSettings["myapp.RenderService"];
if ((urlSetting != null)) {
this.Url = urlSetting;
}
else {
this.Url =
"http://renderv3.staging.mappoint.net/render-30/RenderService.asmx";
}
}
With this code in place, your application uses the service URL specified in the configuration file; when no configuration setting is found, staging service URLs are used instead.
Before we move to the next section, it is important to note that the modifications that you make to the
Reference.cs
or
Reference.vb
file are not
5.3.1.2. Storing your credentials securely
You need to secure MapPoint Web Service credentials through proper application configuration. MapPoint Web Service is a subscription-based web service, and each of your MapPoint Web Service
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %} response; for this purpose, MapPoint Web Service uses digest authentication. When you make a web service method call, you must assign your credentials to the service class. For example, if you are invoking the Find method on the FindServiceSoap class, you need to assign your MapPoint Web Service credentials before calling the method:
//Create service class instance
FindServiceSoap findservice = new FindServiceSoap();
//Assign credentials - Do not do this!
findservice.
Credentials
=
new
System.Net.NetworkCredential("yourid", "yourpassword")
;
//Invoke the method
findservice.find(...);
In this code, the credentials are assigned using the
System.Net.NetworkCredential
object by
There are multiple ways of encrypting your MapPoint Web Service ID and password. In any case, you must develop an encryption library using either the Data Protection APIs or Encryption APIs . The simplest way, of course, is to use the Windows Data Protection APIs (DPAPI ). The DPAPI support two kinds of entropies : machine store entropy and user store entropy . In both cases, you can also provide private entropy , which adds an additional layer of security.
Since the Data Protection APIs are Win32 APIs, you need to build C# wrappers around them. A sample implementation of the DPAPI is included in the companion material (project
Chapter05
); the
DataProtectionCore
sample class can be used for encrypting and
public static string Encrypt(string input)
{
Chapter05.EncryptionUtil.DataProtectorCore dp
= new Chapter05.EncryptionUtil.DataProtectorCore(
Chapter05.EncryptionUtil.Store.USE_MACHINE_STORE);
byte[] encryptedBuffer =
dp.Encrypt(System.Text.ASCIIEncoding.ASCII.GetBytes(input),
null);
return Convert.ToBase64String(encryptedBuffer);
}
Once the user ID and password are encrypted as shown in the previous code, you can store them in the configuration file as follows:
<configuration>
<appSettings>
<add key="MapPointWebServiceID"
value="CAAAAAAADZgAAqAAAQ....tYt9br2PpFHM0AXJd/tIJ/bbb74="/>
<add key="MapPointWebServicePassword"
value="AQAAANCMnd8BFdE ....HTPITIgU6FQcAXJd/tIJXteE8/wQ=="/>
</appSettings>
</configuration>
Now your MapPoint Web Service ID and password are secure in the configuration file; however, your MapPoint Web Service application cannot readily use the encrypted MapPoint Web Service ID and password from the configuration file. You need to write a decrypt routine:
public static string Decrypt(string input)
{
Chapter05.EncryptionUtil.DataProtectorCore dp
= new Chapter05.EncryptionUtil.DataProtectorCore(
Chapter05.EncryptionUtil.Store.USE_MACHINE_STORE);
byte[] decryptedBuffer = dp.Decrypt(Convert.FromBase64String(input)
, null);
return System.Text.Encoding.ASCII.GetString(decryptedBuffer);
}
In this routine, the input string is decrypted back to the original ASCII text. Once you have this decrypt routine, you can always read the encrypted MapPoint Web Service ID and password, decrypt them, and pass them to the MapPoint Web Service:
//Create a find service instance
FindServiceSoap find = new FindServiceSoap();
//Assign credentials
find.Credentials = new System.Net.NetworkCredential(
Decrypt(ConfigurationSettings.AppSettings["MapPointWebServiceID"])
,
Decrypt(ConfigurationSettings.AppSettings["MapPointWebServicePassword"])
);
. . .
//Find places
FindResults results = find.Find(spec);
The Encrypt and Decrypt methods are available in the companion material in the Chapter05 class. 5.3.1.3. Preauthenticate requests for performance gainsFinally, for performance reasons, always assign the PreAuthenticate property on the service SOAP class to True so that your application can avoid any extraneous round-trips to the server just for authentication. For example, on FindServiceSoap service class, set the value as shown: findservice.PreAuthenticate = true; Now that you know how to prepare your development environment for MapPoint Web Service application development, let's get into the MapPoint Web Service object model before we start programming. |