# Wednesday, May 21, 2008
« Creating .NET objects for Mapguide XML s... | Main | Visual Studio 2008 Product Comparison »

As a follow up to my previous post on , I wanted to share some examples of using these new objects, so I created this example of doing some dynamic authoring before the map viewer has loaded.  Currently, all of my work is done using Mapguide Enterprise 2009, however this code should work using Mapguide Open 2.0 as well.  I believe I had this code working using Mapguide 2008 initially, and then migrated it over to the 2009 platform.  Feel free to give that shot if you are still using Mapguide 2008.  Some changes would be needed in the .Net objects project - to remove 2009 specific XSD files and possibly reference some of the older XSDs for things like layers.

One of my first tasks with Mapguide Enterprise was to build a map on the fly.  There were examples for adding layers to the map programmatically after the viewer had loaded, but this didn't match the desired flow of my application.  Also, having come from years of Mapguide 6.5 and lower -  I was trying to avoid as much client side automation as possible.  The new was one of the things that excited me the most about Mapguide Enterprise / Mapguide Open Source

I've pasted the full, commented code here, as well as attached a solution containing the two projects needed.  Note these projects are Visual Studio 2008 projects.  Please feel free to use this code for learning purposes.  If it helps you out, link back to this article =)

If you choose instead to create a new project, be sure to add a project or DLL reference to the OSGeo.Mapguide.Objects.dll file we created previously .  The project I've included here contains both the sample Web Application project, as well as a copy of the .NET objects for Mapguide project.  It should be almost ready for the running.  Also ensure there is a reference to the Microsoft.XML.Schema.Linq namespace added to the project.  Also copy the required .DLL files from the Autodesk provided .NET viewer\bin folder to the web projects bin folder.  I did not include these here as I was not sure of the legality of doing so.

First load up the into your Mapguide repository.  For the purposes of this example, open the Map definition in Mapguide Studio (or equivalent) and remove all the layers and layer groups from the map.  If you forget to do this you will get a Duplicate Object error when you load up the map.  Once that is done, you are ready to try out the code.

You should be able top unzip the zip and open the MGEDynamicAuthoringSample.sln file with Visual Studio.  Pretty much the only thing you may need to change are the constants to match your machine specific items:

 

   1: 'set some contants up - webconfig.ini, map viewer url, Map, Layout and Layer locatinos
   2: Private Const gszWebConfig As String = "C:\inetpub\MapGuideEnterprise2009\WebServerExtensions\www\webconfig.ini"
   3: Private Const gszViewerUrl As String = "http://localhost/mapguide2009/mapviewerdwf"
   4: Private Const gszMapResID As String = "Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition"
   5: Private Const gszLayerFolderResID As String = "Library://Samples/Sheboygan/Layers.Folder"
   6: Private Const gszLayoutResID As String = "Library://Samples/Sheboygan/Layouts/SheboyganAsp.WebLayout"
   7: 'lets run with Administrator for noew to eliminate permission problems.  Update your password as needed, or specify your
   8: 'own credentials if you are comfortable with setting up repository permissions.
   9: Private Const gszMGUser As String = "Administrator"
  10: Private Const gszMGPass As String = "admin"


Once you've changed all the needed settings, you should be good to go.  Run the code in Visual Studio and you should now see a map similar to the default Sheboygan map.  The key difference is that all of the layers will exist within the layer group we created programmatically.

Commented Codebehind:

   1: Imports OSGeo.MapGuide
   2: 'we still need to import and use system.xml, but don't really need to use many parts of the XML
   3: 'functionality =)
   4: Imports System.Xml
   5: Partial Public Class _Default
   6:     '' 'So for this example, we're going to use the sheboygan sample package available from 
   7:     '' ' http://mapguide.osgeo.org/download/releases/2.0.x-samples.  Be sure to grab both the 
   8:     '' ' dotnetviewstample.zip as well as the sheboygan.mgp.  Import the package using
   9:     '' ' the mapguide site administrator.  I've tried to use the default resource paths
  10:     '' ' but some tweaking of map will be needed
  11:     '' ' 
  12:     '' ' Open the map definition in Studio, and remove all the layers from Samples/Sheboygan/Maps/Sheboygan.MapDefinition 
  13:     '' ' we're going to add them dynamically    
  14:  
  15:     Inherits System.Web.UI.Page
  16:  
  17:     'set some contants up - webconfig.ini, map viewer url, Map, Layout and Layer locatinos
  18:     Private Const gszWebConfig As String = "C:\inetpub\MapGuideEnterprise2009\WebServerExtensions\www\webconfig.ini"
  19:     Private Const gszViewerUrl As String = "http://localhost/mapguide2009/mapviewerdwf"
  20:     Private Const gszMapResID As String = "Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition"
  21:     Private Const gszLayerFolderResID As String = "Library://Samples/Sheboygan/Layers.Folder"
  22:     Private Const gszLayoutResID As String = "Library://Samples/Sheboygan/Layouts/SheboyganAsp.WebLayout"
  23:     Private Const gszMGUser As String = "Administrator"
  24:     Private Const gszMGPass As String = "admin"
  25:  
  26:     ''' <summary>
  27:     ''' Page_Load does everything =)  Be sure to copy the dll files from your mapviewernet\bin folder to this projects bin folder.
  28:     ''' I did not include them as that might have violated some autodesk license.    
  29:     ''' </summary>
  30:     ''' <param name="sender"></param>
  31:     ''' <param name="e"></param>
  32:     ''' <remarks></remarks>
  33:     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  34:  
  35:         'setup our siteconnection
  36:         Dim siteConnection As New MgSiteConnection
  37:         siteConnection = CreateMGSession(gszMGUser, gszMGPass, gszWebConfig)
  38:         Dim szSessionId As String = siteConnection.GetSite.CreateSession()
  39:  
  40:         'create our connection to the resource service
  41:         Dim resSvc As MgResourceService
  42:         resSvc = siteConnection.CreateService(MgServiceType.ResourceService)
  43:  
  44:         'get or set the resourceid of the map to load - in this case i'm just going to hard code it
  45:         Dim mapResourceID As New MgResourceIdentifier(gszMapResID)
  46:  
  47:         'load the existing map from the libary into an XML document
  48:         Dim mapXML As XmlDocument = GetResourceXML(resSvc, mapResourceID)
  49:  
  50:         'so at this point we have an XML document.  Let's try using our new OSGeo.Mapguide.Object classes
  51:         Dim newMapDefinition As New OSGeo.MapGuide.Objects.MapDefinition
  52:  
  53:         'to load the xml - call the shared/static method of MapDefinition.Parse on the OuterXML of the XMLDocument
  54:         newMapDefinition = OSGeo.MapGuide.Objects.MapDefinition.Parse(mapXML.OuterXml)
  55:  
  56:         'at this point we have a loaded .NET Object containing the map.  Try using Intellisense to see the different methods
  57:         'Lets add a layer group now
  58:  
  59:         'add any needed layer groups to the map.  In this example we're only going to add one.
  60:         Dim szLayerGroupName As String = "NewLayerGroup"
  61:         Dim szLayerGroupAlias As String = "My Layer Group Alias"
  62:         newMapDefinition = AddMapLayerGroup(newMapDefinition, szLayerGroupName, szLayerGroupAlias)
  63:  
  64:         'get or set the resourceid of the folder that contains our layers to add
  65:         Dim layerPath As New MgResourceIdentifier(gszLayerFolderResID)
  66:  
  67:         'so we now have a layer group in our map.  Lets add the layers
  68:         AddFolderOfLayers(resSvc, newMapDefinition, layerPath, szLayerGroupName)
  69:  
  70:         'at this point our map definition is loaded.  Lets convert it back to XML and save it to the session
  71:         Dim newMapDoc As New XmlDocument
  72:         newMapDoc.PreserveWhitespace = True
  73:  
  74:         Dim szXML As String = newMapDefinition.Untyped.ToString
  75:         newMapDoc.LoadXml(szXML)
  76:  
  77:         'create our 'new' resourceID in the session repository
  78:         Dim newMapResourceID As New MgResourceIdentifier("Session:" & szSessionId & "//" & mapResourceID.GetName() & "." & MgResourceType.MapDefinition)
  79:  
  80:         'save the newly created map in the session repository
  81:         CreateSessionResource(resSvc, newMapDoc, szSessionId, newMapResourceID.GetName, MgResourceType.MapDefinition)
  82:  
  83:         'now lets deal with the layout - we need to load up the library layout, update the map definition, and save it to the repository
  84:         Dim layoutResourceID As New MgResourceIdentifier(gszLayoutResID)
  85:         Dim newLayoutResourceID As New MgResourceIdentifier("Session:" & szSessionId & "//" & layoutResourceID.GetName() & "." & MgResourceType.WebLayout)
  86:  
  87:         'same process here, load the XML, parse the XML into the new .net Object
  88:         Dim layoutXML As XmlDocument = GetResourceXML(resSvc, layoutResourceID)
  89:  
  90:         Dim newLayout As New OSGeo.MapGuide.Objects.WebLayout
  91:         newLayout = OSGeo.MapGuide.Objects.WebLayout.Parse(layoutXML.OuterXml)
  92:  
  93:         'update the map resource ID in the layout to point to our newly created map in the session
  94:         newLayout.Map.ResourceId = newMapResourceID.ToString
  95:  
  96:         'finally go through the motinos to save the layout to the session
  97:         Dim newLayoutXML As New XmlDocument
  98:         newLayoutXML.PreserveWhitespace = True
  99:         newLayoutXML.LoadXml(newLayout.Untyped.ToString())
 100:  
 101:         CreateSessionResource(resSvc, newLayoutXML, szSessionId, newLayoutResourceID.GetName, MgResourceType.WebLayout)
 102:  
 103:         'our last step is to update the src attribute of the iframe with the information needed to load the newly created layout
 104:         SetupIFrame(newLayoutResourceID, szSessionId)
 105:     End Sub
 106:     Private Sub SetupIFrame(ByVal layoutResId As MgResourceIdentifier, ByVal szSessionID As String)
 107:         'build the URL based on our constants, and the layout + session info
 108:         Dim szUrl As String = gszViewerUrl & "?WEBLAYOUT=" & layoutResId.ToString & "&SESSION=" & szSessionID
 109:  
 110:         'update the iframe
 111:         ifrmViewer.Attributes.Add("src", szUrl)
 112:     End Sub
 113:     ''' <summary>
 114:     ''' Adds a layer group to the passed MapDefinition, and returns the updated MapDefinition Object.
 115:     ''' If desired, additional parameters could be added to this to customize the various other properties
 116:     ''' like ShowInLegend etc        
 117:     ''' </summary>
 118:     ''' <param name="mapDef">The loaded MapDefinition obect</param>
 119:     ''' <param name="szLayerGroupName">The Layer Name of the new layer group</param>
 120:     ''' <param name="szLayerGroupAlias">The Layer Alias of the new layer group</param>
 121:     ''' <returns>the passed MapDefinition, with the new layer group added</returns>
 122:     ''' <remarks></remarks>
 123:     Public Shared Function AddMapLayerGroup(ByVal mapDef As OSGeo.MapGuide.Objects.MapDefinition, ByVal szLayerGroupName As String, ByVal szLayerGroupAlias As String) As OSGeo.MapGuide.Objects.MapDefinition
 124:         Dim newLayGRoup As New OSGeo.MapGuide.Objects.MapLayerGroupType
 125:         newLayGRoup.Name = szLayerGroupName
 126:         newLayGRoup.LegendLabel = szLayerGroupAlias
 127:         newLayGRoup.ShowInLegend = "True"
 128:         newLayGRoup.ExpandInLegend = "True"
 129:         newLayGRoup.Visible = "True"
 130:         newLayGRoup.Group = ""
 131:         mapDef.MapLayerGroup.Add(newLayGRoup)
 132:         Return mapDef
 133:     End Function
 134:  
 135:     ''' <summary>
 136:     ''' Adds all layer definitions within the specified repository folder to the specified map
 137:     ''' </summary>
 138:     ''' <param name="resSvc">An open resource service connection</param>
 139:     ''' <param name="newMap">the MapDefinition object to modify</param>
 140:     ''' <param name="resLocation">The folder in the repository to search for layer objects</param>
 141:     ''' <returns>Update MapDefinition object</returns>
 142:     ''' <remarks></remarks>
 143:     Public Shared Function AddFolderOfLayers(ByRef resSvc As MgResourceService, ByVal newMap As OSGeo.MapGuide.Objects.MapDefinition, ByVal resLocation As MgResourceIdentifier, ByVal szLayerGroupName As String) As OSGeo.MapGuide.Objects.MapDefinition
 144:         'get the list of layers in the folder
 145:         Dim resList As OSGeo.MapGuide.Objects.ResourceList
 146:         'use GetAllResources to get a new resList
 147:         resList = GetAllResources(resSvc, resLocation, 1, MgResourceType.LayerDefinition)
 148:  
 149:         'resList items are pretty much a collection of resrouceDocumentLocalTypes so define one of these to use in the for loop
 150:         Dim resItem As OSGeo.MapGuide.Objects.ResourceList.ResourceDocumentLocalType
 151:  
 152:         'define a new layerResID to use in the loop
 153:         Dim layerResID As MgResourceIdentifier
 154:  
 155:         'for each layer - process it and add it to the map
 156:         Dim newLayerType As New OSGeo.MapGuide.Objects.MapLayerType
 157:         For Each resItem In resList.ResourceDocument
 158:             layerResID = New MgResourceIdentifier(resItem.ResourceId)
 159:             'for adding a layer to the map - we must use the MapLayerType object 
 160:             newLayerType = New OSGeo.MapGuide.Objects.MapLayerType
 161:             newLayerType.ResourceId = layerResID.ToString
 162:             'Be sure to specify the name of the 
 163:             newLayerType.Group = szLayerGroupName
 164:             newLayerType.Name = layerResID.GetName
 165:             newLayerType.Selectable = "false"
 166:             newLayerType.ShowInLegend = "true"
 167:             newLayerType.LegendLabel = layerResID.GetName
 168:             newLayerType.ExpandInLegend = "true"
 169:             newLayerType.Visible = "true"
 170:  
 171:             newMap.MapLayer.Insert(0, newLayerType)
 172:         Next
 173:         'return the updated MapDefinition
 174:         Return newMap
 175:     End Function
 176:  
 177:     'Some handy functions
 178:  
 179:     ''' <summary>
 180:     ''' Saves the specified XMLDocument to the session respository
 181:     ''' </summary>
 182:     ''' <param name="resSvc">The open resource service connection</param>
 183:     ''' <param name="xmlDoc">the XMLDocument to save to the session repository</param>
 184:     ''' <param name="szSessionId">String containing the session ID</param>
 185:     ''' <param name="szName">The name of the newly created object in the repository</param>
 186:     ''' <param name="szResourceType">the object type</param>
 187:     ''' <returns></returns>
 188:     ''' <remarks></remarks>
 189:     Public Shared Function CreateSessionResource(ByRef resSvc As MgResourceService, ByVal xmlDoc As XmlDocument, ByVal szSessionId As String, ByVal szName As String, ByVal szResourceType As String) As MgResourceIdentifier
 190:         Dim byteSource As MgByteSource = getByteSource(xmlDoc)
 191:         Dim resID As New MgResourceIdentifier("Session:" & szSessionId & "//" & szName & "." & szResourceType)
 192:         resSvc.SetResource(resID, byteSource.GetReader, Nothing)
 193:         Return resID
 194:     End Function
 195:  
 196:     ''' <summary>
 197:     ''' Returns an MgByteSource for the passed XMLDocument
 198:     ''' </summary>
 199:     ''' <param name="xmlDoc">The XMLDocument to convert</param>
 200:     ''' <returns>MgByteSource of the XMLDocumnet</returns>
 201:     ''' <remarks></remarks>
 202:     Public Shared Function getByteSource(ByVal xmlDoc As XmlDocument) As MgByteSource
 203:         Dim xmlStream As New IO.MemoryStream
 204:         xmlDoc.Save(xmlStream)
 205:         Dim arrBytes() As Byte = xmlStream.ToArray()
 206:         Dim Enc As Encoding = Encoding.UTF8
 207:         Dim docString As String = New String(Enc.GetChars(arrBytes))
 208:         arrBytes = Nothing
 209:  
 210:         Dim arrOutput(docString.Length - 1) As Byte
 211:         Dim nByteCount As Integer = Enc.GetBytes(docString, 0, docString.Length, arrOutput, 0)
 212:  
 213:         Dim byteSource As New MgByteSource(arrOutput, arrOutput.Length)
 214:         byteSource.SetMimeType(MgMimeType.Xml)
 215:  
 216:         Return byteSource
 217:     End Function
 218:  
 219:     ''' <summary>
 220:     ''' returns a loaded XML document of the specified resourceID
 221:     ''' </summary>
 222:     ''' <param name="resSvc">An open connection to the Mapguide Resource Service</param>
 223:     ''' <param name="resId">The MgResourceID of the entity in question</param>
 224:     ''' <returns>A loaded XMLDocument of the specified resource</returns>
 225:     ''' <remarks></remarks>
 226:     Public Shared Function GetResourceXML(ByRef resSvc As MgResourceService, ByVal resId As MgResourceIdentifier) As XmlDocument
 227:         Dim retDoc As New XmlDocument