Note: This article makes references to connecting to MDNS web services via Microsoft's Web Services Extensions 3 (WSE3). This applies only to 6.1.2 and previous. Current versions use Microsoft Windows Communication Foundation (WCF).
Overview
This article will show how to connect to MapDotNet Server web services directly, as opposed to the normal route of working through the ASP.NET controls. There are many reasons to do this: you may want to take advantage of MDNS's map rendering and querying capabilities in an existing application such as a Windows.Forms application or perhaps event connect from a different language/architecture. This particular example will be a Windows.Forms application.
Step 1: Install and configure WSE3
MDNS utilizes
Microsoft's WSE3 for comprehensive security. We need to account for this on the client end in order to send the correct information to the MDNS web service. We will need to:
1) Download and install Microsoft WSE3 (
link)
2) Enable WSE3 in your project:
- Right click on your project in the solutions explorer of Visual Studio.
- Select WSE Settings 3.0...
- Check the "Enable this project for Web Services Enhancements" checkbox in the new dialog
Step 2: Set up the references
Next, we will need to set up our web references to the MapDotNet Server Web Services (This article assumes you already have Visual Studio open with an application created). Right click on your project/website and select the "Add Web Reference..." option:
This will open up the "Add Web Reference" dialog:
This is where we enter the URL to our web service so that Visual Studio can acquire enough information to use the web methods in our application. First, let's add the
MapService, which gives us map rendering capabilities. To get this from an installed version of the MDNS Web Service, go to Start Menu->All Programs->MapDot Net Server v.6.x.x->Services->Map Service. This will open a web browser. Grab the URL and paste into the textbox next to the URL label as above. Click the "Go" button and Visual Studio will connect to your web service. Next, you can name your web service and add it. This will be the namespace you will use in your application. I named mine "MapServiceWS". Click the "Add Reference" button.
A new reference should be added and referenced in your Solution Explorer:
Step 3: Consuming the Services
Now we are ready to start developing with the web methods available to us. I will first make a simple map viewer client. I have dropped two controls onto my Windows Form --a ListBox and a PictureBox. The ListBox will store all of the map IDs available and the PictureBox will show the rendered map;
Next, we add the code to connect to the map. I do this right in the Form constructor:
public Form1()
{
InitializeComponent();
MapServiceWse ms = new MapServiceWse();
// set credentials and policy to try username/pwd
UsernameToken token = new UsernameToken("username", "pwd", PasswordOption.SendPlainText);
ms.SetClientCredential<UsernameToken>(token);
// set policy
Policy policy = new Policy();
policy.Assertions.Add(new UsernameOverTransportAssertion());
ms.SetPolicy(policy);
listBox1.DataSource = ms.GetMapIDs(false);
}
For this example, you will need to reference the following namespaces:
using MapServiceWS;
using Microsoft.Web.Services3.Security.Tokens;
using Microsoft.Web.Services3.Design;
This code constructs the Visual Studio generated MapServiceWse object which is simply a wrapper for the available methods in my web service. It then sets the security policy on the web service which is necessary for WSE3. In this case, we create a UsernameToken and attach it to a Policy object. By default, the MDNS web service does not require a valid username/password so the actual value is ignored (
Read about setting up security).
It then finally makes a web service call to the GetMapID function which provides an array of all the available map IDs. I bind this directly to my ListBox control. You should now be able to run this and see the ListBox control populated:
I want to get a rendered map now, so I attach a handler to the ListBox's SelectIndexChanged event and use the selected value as my MapID to render.
Note: for this code you will need to add the ISC.MapDotNetServer.Common.dll assembly as a reference to your project. This is available in the SDK (C:\Program Files\Common Files\MapDotNet Server 2007\Shared\v6.1.2) and you can also grab it from the bin folder of the web service (C:\Program Files\MapDotNet Server\v6.1.2\MapDotNetServer Web Service\bin).
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string mapid = listBox1.SelectedValue.ToString();
MapRequest mr = new MapRequest();
mr.RequestEnvelope = Map.Deserialize(ms.GetBaselineMapState(mapid)).InitialExtents;
mr.ImageWidth = pictureBox1.Width;
mr.ImageHeight = pictureBox1.Height;
MapResponse mp = MapResponse.Deserialize( ms.GetMap(mapid, mr.Serialize(false), false));
if (!string.IsNullOrEmpty(mp.Error))
{
MessageBox.Show(mp.Error);
return;
}
pictureBox1.ImageLocation = mp.ImageUrl;
}
This code grabs the Map ID from the ListBox. It then creates a
MapRequest object. Here we set the map image width and height according to our PictureBox control. We use the web service method GetBaselineMapState to get the initial extents of our map which we will use to render at.
Finally, we use the GetMap method to actually render our map. We provide it with the map ID, the serialized map request, and a flag saying that we don't want the image streamed (we could just as easily set this to true). This method returns a
MapResponse object. First, we check for errors. If none, then point our PictureBox to the ImageURL returned.
Run the app and provided your mapfile is valid you should see something like:
Note: the out-of-the-box mapfile 'MDNServerSample' will need to be updated to work in this setting. Change:
IMAGEURL "/MapDotNetServerWebService6.1.2/output/"
To:
Querying
We can use the
FeatureService to do spatial queries. First, add this web reference just as we did above for the MapService. In my example, I will capture a mouse up event on the PictureBox and perform a drill-down query on the first layer in the map. I will show the result in a DataGridView I dropped onto my form:
I attach a handler to the MouseUp event of the PictureBox as so:
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
string mapid = listBox1.SelectedValue.ToString();
Map map = Map.Deserialize(ms.GetBaselineMapState(mapid));
Query q = new Query();
q.Layer = map.Layers[0];
q.Fields.Add("*");
QueryRequest qr = new QueryRequest();
qr.ShapeFilterOperation = ShapeFilterOperations.DRILL_DOWN;
Envelope env = map.InitialExtents;
//calculate scale
double scale = Math.Abs(env.MaxX - env.MinX) / pictureBox1.Width;
// the spatial query shape is the clicked point
qr.ShapeFilterSerial = Shape.SerializeShape(
new ISC.MapDotNetServer.Common.Point(
(e.X * scale) + env.MinX,
((((env.MaxY - env.MinY) / scale) - e.Y) * scale) + env.MinY));
qr.Queries.Add(q);
FeatureServiceWse fs = new FeatureServiceWse();
// set credentials and policy to try username/pwd
UsernameToken token = new UsernameToken("username", "pwd", PasswordOption.SendPlainText);
fs.SetClientCredential<UsernameToken>(token);
// set policy
Policy policy = new Policy();
policy.Assertions.Add(new UsernameOverTransportAssertion());
fs.SetPolicy(policy);
//query
QueryResponse qp = QueryResponse.Deserialize( fs.Query(mapid, qr.Serialize(false)));
if (!string.IsNullOrEmpty(qp.Error))
{
MessageBox.Show(qp.Error);
return;
}
//bind
dataGridView1.DataSource = qp.QueryResultTables[0].GetDataTable();
}
This code takes the point we clicked on the PictureBox, converts it to map units, and uses it as the filter in a spatial query against the first layer in the map. The query is run against the Feature Service web service and we bind the result to our DataGridView:
Note: querying will not produce results for the MDNServerSample mapfile as querying/editing is not currently supported against Shapefiles.
Editing and more
From this point, you could add a web reference to the
FeatureUpdateService, connect to editing events on the DataGridView, and update the data on-the-fly. I'll leave this as an exercise for the reader.