Implementing the C# mapscript code (c# mapscript tutorial, part 5)

Posted by on July 26, 2006

Add reference to mapscript

Add the reference to mapscript_csharp.dll (browse to the mapscrip installation folder, for example C:\ms4w\Apache\cgi-bin\mapscript\csharp):

{{:mapserver:tutorial:add_reference.jpg|:mapserver:tutorial:add_reference.jpg}}

Remember that if you didn’t set PATH environment variable to the MapServer dlls you will need to manually copy them under the bin folder of this ASP .NET application.

The c# code for Default.aspx page

This is the complete code to add for the Default.aspx page:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.OleDb; //for dbf connection
using System.IO; //for copying the point shapefile
 
namespace TutorialMapServer
{
	/// <summary>
	/// User Interface for c# MapServer Tutorial
	/// </summary>
	public class _Default : System.Web.UI.Page
	{
		protected System.Web.UI.WebControls.Literal litIdentifyResult;
		protected System.Web.UI.WebControls.DropDownList ddlLayers;
		protected System.Web.UI.WebControls.Button butFullExtent;
		protected System.Web.UI.WebControls.RadioButtonList rblGisTools;
		protected System.Web.UI.WebControls.ImageButton ibMap;
		protected System.Web.UI.WebControls.Button butRefresh;
		protected System.Web.UI.WebControls.CheckBoxList cblLayers;
		protected System.Web.UI.WebControls.Label lblInfo;
		protected System.Web.UI.WebControls.TextBox txtUser;
		protected System.Web.UI.WebControls.Button butClear;
		//private variable for this class
		mapObj map;
 
		/// <summary>
		/// Page Load of Tutorial User Interface
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Page_Load(object sender, System.EventArgs e)
		{
			if(!Page.IsPostBack) //First access to the map
			{
				//send image stream from MapServer to ibMap
				ibMap.ImageUrl = "MapStream.aspx?ACTION=INITMAP";
				//initialize controls
				mapObj map = new mapObj(System.Configuration.ConfigurationSettings.AppSettings["mapFilePath"].ToString());
				//iterate the map layer to populate ddlLayer and cblLayer
				for(int i=0;i<map.numlayers;i++)
				{
					layerObj layer = map.getLayer(i);
					ddlLayers.Items.Add(layer.name);
					cblLayers.Items.Add(layer.name);
					//If this condition is true, the layer is visible
					if(layer.status==(int)mapscript.MS_ON)
					{
						cblLayers.Items[i].Selected = true;
					}
				}
			}
			else //Next accesses to the map, let's get it from session
			{
				map = (mapObj)Session["MAP"];
			}
		}
 
		/// <summary>
		/// Click Event on the Map button control
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ibMap_Click(object sender, System.Web.UI.ImageClickEventArgs e)
		{
			lblInfo.Text = "";
			String Action = "";
			String activeLayer=ddlLayers.SelectedItem.Text;
			//we have to check what GIS tool is needed
			switch(rblGisTools.SelectedItem.Text.ToUpper())
			{
				case "ZOOM IN":
					Action = "ZOOMIN";
					break;
				case "ZOOM OUT":
					Action = "ZOOMOUT";
					break;
				case "IDENTIFY":
					Action = "IDENTIFY";
					break;
				case "ADD POINT":
					Action = "ADDPOINT";
					break;
			}
			//For Identify let's call DoIdentify
			if(Action.Equals("IDENTIFY"))
			{
				DoIdentify(e.X,e.Y,activeLayer);
			}
			//For Add Point let's call AddPoint
			if(Action.Equals("ADDPOINT"))
			{
				String[,] fieldValues = new String[2,2];
				fieldValues[0,0]="POI_USER";
				fieldValues[0,1]=	txtUser.Text;
				fieldValues[1,0]="POI_TIME";
				fieldValues[1,1]= DateTime.Now.ToShortDateString() + ", " + System.DateTime.Now.ToLongTimeString();
				AddPoint(e.X,e.Y,activeLayer,fieldValues);
			}
			//Stream map image to ibMap according to the needed GIS Action
			ibMap.ImageUrl = "MapStream.aspx?ACTION=" + Action + "&X=" + e.X + "&Y=" + e.Y + "&ACTIVELAYER=" + activeLayer;
		}
 
		/// <summary>
		/// Create a full Extent Map
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void butFullExtent_Click(object sender, System.EventArgs e)
		{
			ibMap.ImageUrl = "MapStream.aspx?ACTION=FULLEXTENT";
		}
 
		/// <summary>
		/// Add a point feature to point shapefile with an array of values for dbf
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <param name="activeLayer"></param>
		/// <param name="fieldValues"></param>
		private void AddPoint(Double x, Double y, String activeLayer, String[,] fieldValues)
		{
			//check: this action is valid only for point shapefiles
			pointObj point = pixel2point(new pointObj(x,y,0,0)); //conver the image point in map point
			String shapeFullPath = map.shapepath + "\\" + activeLayer + ".shp";
			shapefileObj shapefile = new shapefileObj(shapeFullPath,-2);
			if(shapefile.type!=(int)mapscript.MS_SHAPEFILE_POINT)
			{
				//notify action
				lblInfo.Text = "This action can be performed only on point shapefiles.";
			}
			else
			{
				/*Alternative way to insert a point in the shapefile using shapeObj:
				//create line to store the point
				lineObj line = new lineObj();
				line.add(point);
				//create shape
				shapeObj shape = new shapeObj((int)MS_SHAPE_TYPE.MS_SHAPE_POINT);
				shape.add(line);
				//add shape to shapefile
				shapefile.add(shape);
				*/
				shapefile.addPoint(point);
				//add record for dbf table
				OleDbConnection cn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + map.shapepath + ";Extended Properties=dBASE IV;User ID=Admin;Password=");
				cn.Open();
				OleDbCommand com = cn.CreateCommand();
				//get field list and value list to use in the query on dbf
				String fieldList = "";
				String valueList = "";
				for(int i=0; i<(fieldValues.Length/2); i++)
				{
					fieldList = fieldList + fieldValues[i,0];
					valueList = valueList + "'" + fieldValues[i,1] + "'";
					if(i<((fieldValues.Length/2)-1))
					{
						fieldList = fieldList + ", ";
						valueList = valueList + ", ";
					}
				}
				com.CommandText = "INSERT INTO " + activeLayer + " (" + fieldList + ") VALUES(" + valueList + ")";
				com.CommandType = CommandType.Text;
				com.ExecuteNonQuery();
				cn.Close();
				//notify action
				lblInfo.Text = "Point added (" + (shapefile.numshapes + 1) + " features in shapefile).";
			}
			shapefile.Dispose();
		}
 
		/// <summary>
		/// Let's do identify
		/// </summary>
		/// <param name="x">x image coordinate for the point to identify</param>
		/// <param name="y">y image coordinate for the point to identify</param>
		/// <param name="activeLayer">layer to identify</param>
		private void DoIdentify(Double x, Double y, String activeLayer)
		{
			litIdentifyResult.Text = "";
			//identify
			layerObj layer = map.getLayerByName(activeLayer);
			if(layer!=null)
			{
				layer.template = "dummy"; //for historical reasons
				pointObj point = pixel2point(new pointObj(x,y,0,0)); //conver the image point in map point
				double tolerance = map.width/100; //we use this tolerance
				if(layer.queryByPoint(map, point, mapscript.MS_SINGLE, tolerance)==(int)MS_RETURN_VALUE.MS_SUCCESS)
				{
					//there is a feature to identify
					resultCacheObj result = layer.getResults();
					if(result.numresults>0)
					{
						int shapeInd = result.getResult(0).shapeindex;
						//int tileInd = result.getResult(0).tileindex;
						layer.open();
						shapeObj shape=layer.getFeature(shapeInd, -1);
						//iterate fields and getting values
						for(int i=0; i<layer.numitems; i++)
						{
							litIdentifyResult.Text += "<BR><B>" + layer.getItem(i) + "</B>=" + shape.getValue(i);
						}
						layer.close();
					}
				}
				else
				{
					//there is nothing to identify
					System.Diagnostics.Debug.WriteLine("Nothing to identify.");
				}
			}
		}
 
		/// <summary>
		/// Conver pixel point coordinates to map point coordinates
		/// </summary>
		/// <param name="pointPixel">pixel point (from map Image)</param>
		/// <returns></returns>
		private pointObj pixel2point(pointObj pointPixel)
		{
			rectObj extent = map.extent;
			double mapWidth = extent.maxx - extent.minx;
			double mapHeight = extent.maxy - extent.miny;
			double xperc;
			double yperc;
			xperc = pointPixel.x / map.width;
			yperc = (map.height-pointPixel.y) / map.height;
			double x=extent.minx + xperc*mapWidth;
			double y=extent.miny + yperc*mapHeight;
			pointObj pointMap = new pointObj(x,y,0,0);
			return pointMap;
		}
 
		/// <summary>
		/// Refresh the map
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void butRefresh_Click(object sender, System.EventArgs e)
		{
			//iterate layers and check visibility
			for(int i=0; i<cblLayers.Items.Count;i++)
			{
				layerObj layer = map.getLayerByName(cblLayers.Items[i].Text);
				if(cblLayers.Items[i].Selected)
				{
					layer.status=(int)mapscript.MS_ON;
				}
				else
				{
					layer.status=(int)mapscript.MS_OFF;
				}
			}
			//send image stream from MapServer to ibMap
			ibMap.ImageUrl = "MapStream.aspx?ACTION=REFRESHMAP";
		}
 
		/// <summary>
		/// Restore the original point shapefile (cleared)
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void butClear_Click(object sender, System.EventArgs e)
		{
			String shapeFullPath = map.shapepath + "\\" + ddlLayers.SelectedItem.Text + ".shp";
			layerObj layer = map.getLayerByName(ddlLayers.SelectedItem.Text);
			if(layer.type!=MS_LAYER_TYPE.MS_LAYER_POINT || layer.connectiontype!=MS_CONNECTION_TYPE.MS_SHAPEFILE)
			{
				//notify action
				lblInfo.Text = "This action can be performed only on point shapefiles.";
			}
			else
			{
				//Clear the point shapefile by copying its copy
				//Create a DirectoryInfo object representing the specified directory.
				DirectoryInfo dir = new DirectoryInfo(map.shapepath);
				//Get the FileInfo objects for every file that belongs to shapefile in the directory.
				FileInfo[] files = dir.GetFiles(ddlLayers.SelectedItem.Text + "Copy.*");
				for(int i=0; i<files.Length; i++)
				{
					//be sure to put a copy of the point shapefile under shapepath, the copy should be called as NameCopy (ie: for POI of this tutorial, we put a shapefile copy called POICopy)
					File.Copy(files[i].FullName, map.shapepath + "\\" + ddlLayers.SelectedItem.Text + files[i].Extension, true);
				}
				//notify action
				lblInfo.Text = "Shapefile cleared.";
			}
			ibMap.ImageUrl = "MapStream.aspx?ACTION=LAYERDELETE";
		}
 
 
		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
 
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    
			this.butRefresh.Click += new System.EventHandler(this.butRefresh_Click);
			this.ibMap.Click += new System.Web.UI.ImageClickEventHandler(this.ibMap_Click);
			this.butFullExtent.Click += new System.EventHandler(this.butFullExtent_Click);
			this.butClear.Click += new System.EventHandler(this.butClear_Click);
			this.Load += new System.EventHandler(this.Page_Load);
 
		}
		#endregion
 
	}
}

The c# code for MapStream.aspx page

This is the complete code to add for the MapStream.aspx page:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
 
namespace TutorialMapServer
{
	/// <summary>
	/// MapStream produce an imagestream for the ibMap control at the Default.aspx page
	/// </summary>
	public class MapStream : System.Web.UI.Page
	{
		//private variable for this class
		mapObj map;
		rectObj originalExtent;
 
		/// <summary>
		/// Zoom Mode Enumerator
		/// </summary>
		private enum ZOOMMODE
		{
			ZoomIn = 0,
			ZoomOut = 1
		}
 
		/// <summary>
		/// Do a Map Action and send an image stream
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Page_Load(object sender, System.EventArgs e)
		{
			//read map if existing, otherwhise create a new one from map file
			map = (mapObj)Session["MAP"];
			if(map==null)
			{
				map = new mapObj(System.Configuration.ConfigurationSettings.AppSettings["mapFilePath"].ToString());
				originalExtent = new rectObj(map.extent.minx, map.extent.miny, map.extent.maxx, map.extent.maxy, 0);
				Session["ORIGINALEXTENT"]=originalExtent;
			}
			originalExtent = (rectObj)Session["ORIGINALEXTENT"];
			//read x,y
			Double x=0;
			Double y=0;
			if(Request.QueryString["X"]!=null && Request.QueryString["Y"]!=null)
			{
				x = Double.Parse(Request.QueryString["X"].ToString());
				y = Double.Parse(Request.QueryString["Y"].ToString());
			}
			//let's see which action is necessary
			String Action = Request.QueryString["ACTION"].ToString().ToUpper();
			switch(Action)
			{
				case "ZOOMIN":
					DoZoom(ZOOMMODE.ZoomIn,x,y);
					break;
				case "ZOOMOUT":
					DoZoom(ZOOMMODE.ZoomOut,x,y);
					break;
				case "FULLEXTENT":
					DoZoomFullExtent();
					break;
			}
			//refresh
			RefreshMap();
			//store in session
			Session["MAP"]=map;
		}
 
		/// <summary>
		/// Refresh MapServer map and send the image stream to output
		/// </summary>
		private void RefreshMap()
		{
			using(imageObj image = map.draw())
			{
				byte[] img = image.getBytes();
				using (MemoryStream ms = new MemoryStream(img))
				{
					System.Drawing.Image mapimage = System.Drawing.Image.FromStream(ms);	
					Bitmap bitmap = (Bitmap)mapimage;
					bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
				}				
			}
		}
 
		/// <summary>
		/// Do a zoom in or zoom out
		/// </summary>
		/// <param name="zoomMode">zoomin or zoomout</param>
		/// <param name="x">x image coordinate</param>
		/// <param name="y">y image coordinate</param>
		private void DoZoom(ZOOMMODE zoomMode, Double x, Double y)
		{
			//Do Zoom In
			if(zoomMode==ZOOMMODE.ZoomIn)
			{
				map.zoomPoint(2, new pointObj(x,y,0,0), map.width, map.height, map.extent, null);
			}
			//Do Zoom Out
			if(zoomMode==ZOOMMODE.ZoomOut)
			{
				map.zoomPoint(-2, new pointObj(x,y,0,0), map.width, map.height, map.extent, null);
			}
		}
 
		/// <summary>
		/// Do a Full Extent (return to Origina Extent)
		/// </summary>
		private void DoZoomFullExtent()
		{
			map.extent = originalExtent;
		}
 
		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
 
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    
			this.Load += new System.EventHandler(this.Page_Load);
 
		}
		#endregion
	}
}

Code flow

The code is extensively commented, so you should have not difficulties to follow it.

  • the client from the browser request a map. If it is the first map the INITMAP action is performed and the first map from MapServer is generated
  • the MapServer map is generated from the mapObj from the mapscript library, by accessing to the data (shapefiles) by the Map File
  • the map is streamed to the image button control in the default.aspx page from the MapStream.aspx page
  • the mapObj is stored in session for following access from the client
  • all the GIS actions (Zoom In, Zoom Out…) from the default.aspx page are performed still by the MapStream.aspx page

schema flow of tutorial code

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • Furl
  • LinkedIn
  • Reddit
  • StumbleUpon
18 Comments on Implementing the C# mapscript code (c# mapscript tutorial, part 5)

Closed

  1. kriss says:

    can u help me in writing the above c#mapscript code in jsp

  2. asmaa says:

    Hi all I’m in 4th year at faculty of computer and information science,
    I’ll make graduation project about map server and in need to source code to complete in it, with environment c# can any one to help me or get it plllzzzz.

  3. stelios says:

    Hi! I am trying to extend the functionality of the MapServer Tutorial’s MapStream.aspx.

    What I want to do is to implement Pan and PositionClick functionality except for ZoomIn, ZoomOut and Identify.

    Are there any sample codes doing this?
    Is this possible to be implemented with C# and MapStream.aspx?

    Thanks!

  4. Paolo Corti says:

    stelios, you can do that
    take a look at how it was implemented with Flash here:
    http://www.paolocorti.net/public/wordpress/index.php/2006/10/26/mapflashviewer-framework/

    convert the Flash UI in javascript and you should be fine
    good luck!

  5. BeautifulLife says:

    I tried to build the above solution using .NET 2.0, but it gave the following error:
    Error 2 ‘ASP.default_aspx.GetTypeHashCode()’: no suitable method found to override c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\tutorialmapserver\93bfa9fe\bb979f8a\App_Web_wmqpjty3.0.cs

    Please help..

  6. Nuno Sénica says:

    Hi Paolo,

    First, me congrats for your great work / website.

    I was a ESRI software developers until the moment, and now I’d like to try and explore MapServer.

    I’d like to know if its possible to develop a project using:

    - MapServer
    - Mapscript C# .NET 2.0
    - Data from PostGIS + Raster files
    - OpenLayers

    I took a look at your tutorial but there isn’t a connection with OpenLayers, also the map image is a single image (I’d prefer some kind of tiling so that the image doesn’t desapear before rendering a new image).
    I also don’t want to use WMS, but call vectorial data.

    Do you have any advise and code samples so I can get started ??

    Thanks a lot : )

    Regards,
    Nuno Sénica.

  7. Paolo Corti says:

    Hello Nuno
    I don’t know OpenLayers but it looks that you need to use WMS in order to use it, since what I understand. And then you would do everything with javascript and not with .NET.
    For the rest, you can do everything you want, but you have to use another UI interface.
    Good luck!

  8. Nuno Sénica says:

    Hi again Paolo,

    Thx for your reply.

    What abou the map? It’s only possible to use an imagebutton control ?
    Because this renders only a single tile/image…

    Regards,
    Nuno.

  9. Paolo Corti says:

    I am sure you can implement that, but you would need to server-side-code your tiles from an AJAX UI you should write from scratch (maybe modifing OpenLayers?).
    Or you can still use WMF, and then everything is fine with OpenLayers, you need to write only bit of code.
    I do not think that MapServer has another tool similiar to tile4ms, and that is for shapes, not for PostGis.
    Let me know how you implemented this, i am curious ;-)

  10. Nuno Sénica says:

    Ok Paolo… ; )

    By the way,

    How do I query a PostGIS layer?? I tried layer.querybyattributes but it seems that works only with shapefiles!?

    layerObj layer = map.getLayerByName(activeLayer);
    layer.template = “dummy”;

    layer.queryByAttributes(map, “country”, “country = ‘PORTUGAL’”, mapscript.MS_MULTIPLE);

    layer.getResults() returns always 0!

    ##########################

    Another question, how do I “identify” a point on the map BUT for multiple layers? Instead of the single active layer only??

    Regards,
    Nuno.

  11. jlrojas says:

    hi paolo, many thanks for these great tuto/webpage, i follow the tuto but i have 4 errors in visual studio..

    2 in default.aspx
    the type or namespace name ‘mapobj’ could not be found line 32..

    pointobj line 226

    2 in mapstream.aspx.cs
    mapobj line 21
    rectobj line 22

    all the same error could not be found

    i appretiate your help..
    manny thanks for all..

  12. Nikadib says:

    Hi,
    I also have a problem similar to jlrojas.
    Could any expert help us?

  13. Nikadib says:

    Jrojas,
    I know what the problem. I’ve settle it now.
    You should insert in coding this “using OSGeo.MapServer;”:-

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Web;
    using System.Web.SessionState;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.Data.OleDb;
    using System.IO;
    using OSGeo.MapServer;

  14. Nikadib says:

    After settle this problem, I face with other problem which the map doesn’t appear in the imageButton (ibMap).
    When I trace the coding, the system read all layer. But the map doesn’t appear. i don’t know why.
    Can anyone help me.

  15. jlrojas says:

    thanks Nikadib, i try it today….
    Many thanks for your help….

  16. johnny says:

    hi paolo

    great example but not working for me

    this is my problem

    if(layer.status==(int)mapscript.MS_ON)
    {
    cblLayers.Items[i].Selected = true;—-> in this line ERROR

    visual web developer 2005 C#
    postgre 8.2 windows
    postgist

    please help meee

    cheer s from chile

  17. johnny says:

    hi paolo

    great example but not working for me

    this is my problem

    if(layer.status==(int)mapscript.MS_ON)
    {
    cblLayers.Items[i].Selected = true;—-> in this line ERROR TypeInitializationException mapscript

    visual web developer 2005 C#
    postgre 8.2 windows
    postgist

    please help meee

    cheer s from chile

  18. nitin says:

    hi!
    i am just studing on .net,& i am developing
    an application for which i need a code for zooming & zoom out an image.
    plz help me out.
    thnx.