August 6, 2009

Configuring Mapguide Enterprise 2009 and 2010 on the same machine

Filed under: Mapguide — Tags: — Darrin Maidlow @ 1:57 pm

So I’m a little behind on the times.  Yes I’ve finally started making the switch from Mapguide Enterprise 2009 to MGE 2010.   However, I need to keep 2009 around a little bit longer.  This resulted in wanting to configure both 2009 and 2010 on the same server.  Configuring Mapguide enterprise 2009 and 2010 on the same machine is possible, and even beneficial in a development environment.  Less VMs or servers can be a good thing in these days of crazy .  Autodesk however, recommends against doing this in a production environment.   You should probably heed this advice if this Mapguide installation is important – even from a workgroup development point of view.   Note, these steps should be relevant for the Mapguide Open Source equivalents – though I have not tried it.

After installing Mapguide 2010 (both server and web tier) on a server running 2009 and updating the license manager appropriately, you’ll notice that the service is not running.  Attempts to start the service will result in an error message logged in the Windows Application Log that looks a little bit like this:

The description for Event ID ( 0 ) in Source ( MapGuide Enterprise 2010 Server ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Port 2801 is not available, please try using a different port.

So we need to setup one of the Mapguide installations to use a different set of ports.  I’ve chosen to modify the behavior of Mapguide 2010, though these changes could be made for Mapguide 2009 instead.   For this process we’ll need three free ports.  For simplicity its nice to keep these ports sequential.  You will need to ensure that the ports you choose are available on your system.

First we need to edit the serverconfig.ini in the C:\Program Files\Autodesk\MapGuideEnterprise2010\Server\Bin folder.   First lets change the Port in the AdministrativeConnectionProperties section from 2800 to lets say 3800.   Next in the ClientConnectionProperties section change the port to 3801.  Finally change the port in SiteConnectionProperties to 3802.

Next we need to edit the webconfig.ini in the C:\Program Files\Autodesk\MapGuideEnterprise2010\WebServerExtensions folder.  We need to update the port numbers in this config to match the numbers in the server config.  Remember the web config is the client that will usually be consuming the server service.  Finally, as the configuration settings for the web tier may be cached you should restart IIS using iisreset.exe.  This will clear the cached port configurations and Mapguide Studio / Mapguide Administration will now work properly.

Once that is done, the 2009 repository can be migrated to 2010 by following the steps included in the Help/MGE2010UpgradingWindows.htm file on your installation disc/folder.

PHP Problems

Once MGE 2010 has been installed I had a problem with PHP.  Multiple PHPs can be bad news.  I’ve found that running both MGE 2009 and 2010 using the PHP provided with 2010 seems to do the trick.  First you will need to edit the Windows system path.  Update the path variable there to point to the 2010 PHP installation.  If a 2010 path variable exists already – remove the 2009 path.  Next open the IIS manager and ensure that both the MGE 2009 and MGE 2010 virtual directory trees are pointing to the MGE 2010 php extension in the Application Extension Mappings.

Once these changes have been made, do a quick IISreset and you should now be able to login to both the Mapguide admins, as well as have Mapguide Studio connect to the appropriate servers.  Again – this setup could have issues – so consider your environment and needs before configuring a server with both releases of Mapguide.

Remote Web Tiers

If you need to run a shared Mapguide server with web tiers installed on individual development machines don’t forget to set the ports on each development machine.   The Mapguide installer will prompt for the Mapguide server IP address – but the webconfig.ini will need to be updated with the appropriate ports manually.  Not doing do will result in your web tier talking to the 2009 server – and much confusion =)

Finally one note on IP addressees and remote web tiers.  If you plan to use a remote web tier – make sure your Mapguide server is setup using the actual IP address of the server and not 127.0.0.1.  If your Mapguide server is configured with 127.0.0.1, you will get a “Cannot establish connection.” error on the remote web tiers when attempting to create and use a session.  Using real IP addresses (either internal or external) will prevent this error from occurring.

Technorati Tags:

October 22, 2008

Mapguide Enterprise 2009 Update 1 (For Windows)

Filed under: Mapguide — Tags: — Darrin Maidlow @ 12:09 pm

Yay.  Autodesk today released an update for both the Mapguide Enterprise Web Tier, Server and Studio.  This release should catch Enterprise up a little more closely to the Open Source edition.  A PDF with containing some of the changes can be found   Some of these updates are pretty critical (ie. the FireFox 3 takes out your Mapguide server).  Looks like many performances updates have made it in also.

Thanks Autodesk! =)

Technorati Tags:

September 26, 2008

Developing with Mapguide Enterprise / Open Source in a shared server environment

Filed under: Mapguide — Tags: — Darrin Maidlow @ 7:41 pm

I have enough junk running on my development machine.  In an effort to try and keep my workstation speedy – I don’t install any unnecessary services (Oracle server, Mapguide Server etc) on this machine.  In a larger development environment, running multiple servers on local development machines has a few other less than desirable results.  For example licensing issues and costs could increase, data management can become more complex, and just managing the extra services on N machines could cause a lot more work for your already overworked IT guy.

So instead I have centralized my server resources into a nice VM setup running on my beefy Dell server.  Now, regardless of which machine I use to develop I can still access the same data sets.  This is especially nice when traveling.  Specifically Mapguide Server and web tier are installed on my development web server.  When coding, I will either use my local IIS or the built in Visual Studio web server.  This poses one problem when working with Mapguide.  Referencing the web tier on the shared server from another web server will result in (XSS) errors.  Basically, javascript on one web server cannot access javascript code on another web server, which under most circumstances is a good thing.  When trying to develop using the Mapguide Web API on a central Mapguide server this poses a problem as the web tier API is wholly contained within the virtual directory on another server.  Gotta love when ’security’ jumps up bites us in the behind.

The simple solution to this problem is to install the Mapguide web tier on every development machine.  This will require that each development machine have a web server installed, but chances are that is already the case.  When installing the web tier be sure to have the IP address of the Mapguide server handy as it will needed during the install.  Once the web tier is running locally, reference the local web tier in your URLs and the cross site scripting vulnerabilities go away!  If you’re running the 64 Bit version of Vista on your development machine, check out my post installing the

Technorati Tags:

August 30, 2008

Increase Mapguide Enterprise/Open Performance with Javascript Compression using the YUI Compressor

Filed under: Mapguide — Tags: , — Darrin Maidlow @ 7:18 am

Javascript compression is something I had on my list for the next major release of RADE.  RADE is not quite ready for this step yet, so I thought I would give it a shot on Mapguide Enterprise and see what kind of results it would yield.  For a small site or an internal site this will probably not yield significant benefits.  However if you run a large public site javascript compression could squeeze out some more performance as well as save you on bandwidth costs.  Yahoo has a good article on .

I did some brief looking around and word on the internets is that the is one of the better compressors out there.  The YUI compressor is an open source java applet.   This *should* work with Mapguide Open, heck this might even be done already in MGOS – but I am only using Enterprise so I cannot confirm, deny, or test this.  

Some of the key things the compressor will do:

  1. remove all comments
  2. remove all white space and line breaks
  3. rename all local variables and parameters to single characters

The YUI compressor should not alter variable values or your logic in any way.

To use the YUI compressor you will need to .  Note that if you have the Oracle client installed, you probably have Java already  Once you have Java, you can download a copy of the (I’m going to start referring to it as the YC now…).  If you don’t feel like downloading Java and the YC – I’ve attached the processed files at the bottom of this post.

Lets first look at the javascript shipped with Mapguide Enterprise.  If you browse to your web server extension viewer files (the default location is C:\Program Files\Autodesk\MapGuideEnterprise2009\WebServerExtensions\www\viewerfiles I believe) you will see ten javascript files.  If you choose to process these files on your own please back them up first.  Don’t blame me if you don’t backup your files and something goes wrong =).

Before YC:

Mapgude Enterprise Javascript before YUI Compression

Using the YC is simple:

   1: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\browserdetect.js browserdetect.js

 

Update the paths to Java and the YC as per your environment.  Using the handy dir /B *.js > go.bat I created a batch file of all the javascript files in the viewerfiles folder.  Be sure to run this from a dos window in the viewerfiles folder, or update the paths.  You will also need to create the comp folder in viewerfiles.   Quick cut and pasting created the following batch file:

   1: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\browserdetect.js browserdetect.js
   2: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\contextmenu.js contextmenu.js
   3: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\digitize.js digitize.js
   4: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\hashtable.js hashtable.js
   5: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\initdwfctrl.js initdwfctrl.js
   6: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\legend.js legend.js
   7: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\numfmt.js numfmt.js
   8: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\pngfix_map.js pngfix_map.js
   9: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\sarissa.js sarissa.js
  10: c:\oracle\product\10.2.0\client_1\jdk\bin\java.exe -jar f:\utils\YUICompress\yuicompressor-2.3.6\build\yuicompressor-2.3.6.jar -o comp\wz_jsgraphics.js wz_jsgraphics.js

 

(*Sorry about the overlap.  I’m working on a new layout and am addressing that in there)

Running that output all of the compressed of the files down somewhat, to pretty significantly.

Mapgude Enterprise Javascript After YUI Compression

A quick comparison of one of the function calls:

   1: function MenuData(menuName, arrowHeight, scrollInc, scrollDelay, minSize, iconScrollUp, iconScrollUpDisabled, iconScrollDown, iconScrollDownDisabled, owner, withIFrame, bkColor)
   2: function MenuData(F,H,I,K,E,G,D,J,A,C,B,L)

 

As you can see – the savings can be significant.

I’m not using the yet so I did not process those files, but I did check some of the JS in there and each script file had a huge header comment.  It looks like Fusion could also benefit from some compression action.  Please note, I’ve been running my web tier using this script for a day or two.  I’ve not run any serious testing on this code – so try this at your own risk.  You did make that backup I suggested, right?  That said, I have not personally experienced any problems yet.  Also, should you compress your viewerfiles and have problems be sure to try your backups.  Especially before calling your dealer or Autodesk for help. (sorry product support and ADN guys.  Please don’t hate me =] ).

if you would rather not run the YC yourself.

Enjoy!

July 30, 2008

Passing a Large Mapguide Selection XML to a New Window Using Dynamic Forms and Javascript

Filed under: Mapguide — Tags: , — Darrin Maidlow @ 11:22 pm

Everyone knows there is a , right?  Well ok, maybe you didn’t – but there is.  What that limit is depends on the browser.  There is a lot of conflicting information out there on the magical .  An RFC defines it, but no one really seems to pay attention to those anyhow.  (Are you listening Microsoft, of course you are! =]).  Anyhow, for IE, the query string length is usually around 2000 characters.

However, in most cases you’re better off using a form and posting your data up to the server side that way, as the limitations on data are so large you will likely not need to worry about them.  Sometimes, query strings can also show your users just a little too much information – though I’m by no means a proponent of "security through obscurity" hiding a little bit more from your users will keep the curious ones a little more in check =).

When working with / we need to grab some potentially massive XML strings from the MgMap object and pass these along to the server side for processing.  Take the selection XML from the MgMap object, even a single entity selection can use a significant portion of the characters available in the query string.  On top of that, passing this data via query string requires that the data be URL encoded, using even more of our precious query string characters.

Depending on the design of your application it may not always be feasible to define a hard coded form, or even a form defined server side using ASP.NET.  In some cases (you guessed it – my case) you may want to use javascript and do all the work on the client side to define a form and pass the data long that way.

Well you’re in luck, I found a pretty nice solution (WELL, at least I’m liking it  =]).   I’m kicking myself for not realizing this long ago, but oh well.  So the following javascript function demonstrates how to build, add, populate, and submit a form on the fly using some information from the MgMap object.

   1: function postData()   
   2: {   3: //get the map   
   3: mapObj = GetMap();   
   4:  
   5: //define the new form   
   6: var newForm = document.createElement("form");   
   7: //set the method to POST - the opposite of query strings..   
   8: newForm.method="POST";  
   9:  //add the new form to the current document  
  10:  document.body.appendChild(newForm);  
  11:  
  12:  //lets get some data and add it to the form  
  13:  AddFormElement(newForm, "MapName", oMap.GetMapName());  
  14:  AddFormElement(newForm, "SID", oMap.GetSessionId());  
  15:  //be sure you escape the selection XML - or you will get an error on post about a   
  16:  //"potentially dangerous form value".  Remember on the server side to Server.UrlDecode() it  
  17:  AddFormElement(newForm, "sel", escape(oMap.GetSelectionXML()));  
  18:  
  19:  //lets create our new window  
  20:  var szTarget = "targetWin"  
  21:  newForm.target = szTarget;  
  22:  //set the name/path of the ASPX file you want to process your form with  
  23:  newForm.action = "/url_to_open/file.aspx"  
  24:  
  25:  //open a new window to submit the form to.  Its a good idea to have a blank.htm so you don't get a file not found error  
  26:  var oWin = window.open("blank.htm",szTarget,'menubar=yes, resizable=yes,scrollbars=yes, status=no,toolbar=no,width=300, height=300');  
  27:  
  28:  //give the window focus.  Users like this  
  29:  oWin.focus();  
  30:  
  31:  //submit the form - it will now open in the new window  
  32:  newForm.submit();  
  33:  //remove the form from the document, we're done with it  
  34:  document.body.removeChild(newForm);  
  35:  }  
  36:  
  37:  function AddFormElement(form, elementName, elementVal)  
  38:  {  
  39:      var newElement = document.createElement("<input name='" + elementName + "' type='hidden'/>");  
  40:      newElement.value = elementVal;  
  41:      form.appendChild(newElement);  
  42:      return form;  
  43:  }

 

On the server side, you can now access this data from ASP.NET using Request.Form, for example Request.Form("MapName") would give you the map name.  Don’t forget when retrieving the selection XML to run that through Server.UrlDecode, or HttpUtility.UrlDecode.

As usual, any comments, bugs, or rotten fruit – send em my way.  Enjoy!

Mapguide 2009 / OS 2.0 Get Selected Key Values VB.NET Example and the dreaded MgSelection.GenerateFilter Issue

Filed under: Mapguide — Tags: , — Darrin Maidlow @ 2:12 am

Tonight I came across the .  I had read about it, and made a mental note that one day it would be an issue.  That note wasn’t very good, and I completely forgot about it.   I was wrapping up the updates around the report this eve and fortunately I bothered to select the entire map and run through a report.

RADE Report - but what, only 20 records returned?

Report looked good.  The results were sorting, checkboxes working.   Wait a minute, I selected the entire map.  There should be more than twenty items returned.  So a quick search of my twelve thousand saved e-mails from the turned up what needed to be done.  Fortunately Autodesk added a GenerateFilters call to MgSelection.  This call returns an MgStringCollection of filters.

Basically the solution to this problem is to use GenerateFilters instead of GenerateFilter, and loop through the results.  Each time, appending the returned keys to the complete list.  For example:

   1: Public Shared Function GetSelectedKeysString(ByRef siteConn As MgSiteConnection, _
   2:     ByRef resSvc As MgResourceService, ByVal oMap As MgMap, ByVal SessionId As String, _
   3:     ByVal SelectionXML As String, ByVal layerResID As MgResourceIdentifier, _
   4:     ByVal keyFieldName As String) As String
   5:  
   6:     Dim szKeys As String = ""
   7:     Dim oSel As New MgSelection(oMap)
   8:     oSel.FromXml(SelectionXML)
   9:     Dim curLay As MgLayerBase
  10:     'isolate the layer
  11:     For Each layerItem As MgLayerBase In oSel.GetLayers
  12:         If layerItem.Name = layerResID.Name Then
  13:             curLay = layerItem
  14:         End If
  15:     Next
  16:  
  17:     Dim featSvc As MgFeatureService = siteConn.CreateService(MgServiceType.FeatureService)
  18:     Dim queryOptions As New MgFeatureQueryOptions
  19:     Dim featureClassName As String = curLay.GetFeatureClassName
  20:     'workaround using GenerateFilters and looping through the results as needed
  21:     Dim featureReader As MgFeatureReader
  22:     Dim filters As MgStringCollection = oSel.GenerateFilters(curLay, featureClassName, 20)
  23:     Dim filterCnt As Integer = 0
  24:     While filterCnt < filters.GetCount
  25:         queryOptions.SetFilter(filters.GetItem(filterCnt))
  26:         featureReader = featSvc.SelectFeatures(New MgResourceIdentifier(curLay.GetFeatureSourceId), featureClassName, queryOptions)
  27:         While featureReader.ReadNext
  28:             If szKeys = "" Then
  29:                 szKeys = ConvertPropertyToString(featureReader, keyFieldName)
  30:             Else
  31:                 szKeys &= "," & ConvertPropertyToString(featureReader, keyFieldName)
  32:             End If
  33:         End While
  34:         featureReader.Close()
  35:         featureReader.Dispose()
  36:         filterCnt += 1
  37:     End While
  38:     Return szKeys
  39: End Function

 

In this code, we get the selection from the MgMap object and then isolate the layer in question.  Then we generate the collection of filters and loop through them.  Each time, adding the appropriate value to the list of keys.  Note the use of ConverPropertyToString, this needs to be used to ensure that the various data types are converted over to string.

I’ve included this function as well as a couple other handy related ones in the attached zip file

.  If you’re looking for a C# example of how to use GenerateFilters one is provided in the .

After making these changes my reports now look all proper! hurray.  Maybe I can hit the sack now?  nahh.

RADE report - but this time everything looks ok 

July 7, 2008

Mapguide Enterprise – Cannot Select Items in DWF and AJAX viewer – Again

Filed under: Mapguide — Tags: , , — Darrin Maidlow @ 10:41 pm

I had another problem with Mapguide Enterprise 2009 recently pertaining to objects not being selectable.  Unlike my previous post on errors caused by layers, no errors were logged to the Mapguide server logs.  This problem is very likely specific to the enterprise version, as I was using the Autodesk FDO Provider for Oracle.

So a data connection was created pointing to the Oracle 10g schema.  This database contained a number of tables containing Lat/Long point geometry entities.  I created a layer pointing to the table in question.  I created a layer pointing to that data connection.  At this point the entities showed up as expected in the both the DWF and the AJAX viewers.  Once again, I could not select any of the entities.  I checked the server logs, no errors were reported.

In troubleshoot mode, I tried just about everything I could think of but nothing would work.  I simplified the theme, created new layers, removed all other layers from them map.  Eventually I created a new layer from another table.  Luckily, the entities on this layer could be selected.  It must be a problem with the underlying data.  On a hunch, I checked the table definitions – specifically looking at primary keys.  The selectable layer had a primary key defined, the problem layer did not.  (Good thing I cannot take credit for creating this source data =))

So, I created a primary key on the problem table, did a touch on the layer definition (opening the definition in Studio and saving it without any changes) and then left for twenty minutes.  I’m thinking there is some sort of caching going within the server, and I’m not sure how it works.  Immediately reloading the map after adding the primary key did not work – the entities were still not selectable.  When I came back – the items in the viewers were now selectable.

So long story short, if again you cannot select map entities using the Autodesk FDO Provider for Oracle ensure that the source table has a primary key defined.  Hopefully this saves someone some grief =)

June 25, 2008

Easy color ranges for developers in Mapguide Studio 2009

Filed under: Mapguide — Tags: — Darrin Maidlow @ 6:30 pm

Typically developers are color stupid (myself included).  I’ve seen some really really ugly maps.  I’ve created some really really ugly maps.  With Mapguide 6.5 in particular – I gave up on trying to create visually appealing maps.  The 255 colors, in the ranges defined I just could not do it.

With Mapguide Enterprise – I may have found a solution.  Recently I created a themed layer for municipalities.  There were twenty five municipalities in a single spatial table.  Each municipality had a unique code.   In an effort to bang these off quickly I added the twenty five municipalities and the filter condition.   Next I entered the twenty five legend labels.

Here is the developer friendly method I came up with creating a somewhat visually appealing color range.  In the first condition I set first set the transparency to 50%.  The transparency affects the resulting color.  Select the color combo and choose "More Colors".  This should bring up the custom color dialog.  First, select one of the "Custom Color" boxes and set the Hue to 0. Next I created a color I wanted to use as my starting shade.

At this point, I saved the color using the "Add to Custom Colors" button.  Your form should look something like this:

Mapguide Color Dialog

Click OK a couple of times and your first condition should be set.  Next I selected my next condition, and clicked the color combo again choosing "More Colors" once again.  This time, select the saved custom color and it should reset the form with the previously saved shade.  At this point I incremented the Hue by 20 to 20.  Click ok a couple of times and repeat.  I was not re-saving my shade, though I suppose that might have made sense.  Each time you repeat this process increase the hue by 20 until you hit the max of 239.

If needed, and you do hit the max hue start the process over starting with another complimentary base shade with a hue of 0. Using a hue increment of 40 might have resulted in more distinct colorations and may be a good idea.

I think it turned out OK, but then again as I stated earlier – I’m color stupid. 

Resulting Color Range

June 24, 2008

Convert Mapguide 6.5 colors to Mapguide Enterprise/Open Source/AutoCAD RGB equivalents

Filed under: Mapguide — Tags: — Darrin Maidlow @ 11:59 pm

I’ve been authoring some test data for my ongoing Mapguide Enterprise \ MGOS work.  For consistency with my existing tabular test data, I need to migrate some Mapguide 6.5 maps over to Enterprise.  This is quite the chore.  I really wish Autodesk would have kept updating the Mapguide 6.5 and bring that up to support a current release of Mapguide.  Even with the tools flaws, it was still a good start on migration – but oh well, that’s another rant completely..and maybe another side project that I just don’t have time for =)

Anyhow, I wanted to share the .  I can’t believe I hadn’t found this page sooner.  A fantastic, and crucial reference.   Tons of useful settings for the chart generator.  Show the hex codes for using the colors in HTML, Decimal RGB values for Mapguide Enterprise \ Autocad.  The colors under the Decimal heading are the RGB values – ordered in Red, Green, Blue.  I’ve been using the chart in .

Thanks Pima County.  Hopefully, you guys were able to come up with a programmatic method of creating this chart.  I’d hate to be the guy tasked with ‘eyedropping’ all these colors using Photoshop or something.

The decimal values by the way should work with AutoCAD too.

 

Technorati Tags:

May 21, 2008

Dynamic Authoring in Mapguide Enterprise – Before the Viewer has Loaded

Filed under: Mapguide — Tags: , — Darrin Maidlow @ 11:38 pm

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
 228:         retDoc.PreserveWhitespace = True
 229:  
 230:         Dim szXML As String = resSvc.GetResourceContent(resId).ToString()
 231:         Dim nByteCount As Integer
 232:         Dim arrByte(szXML.Length) As Byte
 233:         nByteCount = Encoding.UTF8.GetBytes(szXML, 0, szXML.Length, arrByte, 0)
 234:  
 235:         Dim memStream As New IO.MemoryStream(arrByte)
 236:         retDoc.Load(memStream)
 237:         Return retDoc
 238:     End Function
 239:  
 240:  
 241:     ''' <summary>
 242:     ''' Create a new mapguide session and return the resulting session ID
 243:     ''' </summary>
 244:     ''' <param name="szMGUser">Valid mapguide user name</param>
 245:     ''' <param name="szMGPass">Valid password for the specified mapguide user name</param>
 246:     ''' <param name="szMGWebTier">The path to the Mapguide web tier (valid on the mapguide web server</param>
 247:     ''' <returns>MgSiteConnection - the newly created mapguide site connection</returns>
 248:     ''' <remarks></remarks>
 249:     Public Shared Function CreateMGSession(ByVal szMGUser As String, ByVal szMGPass As String, ByVal szMGWebTier As String) As MgSiteConnection
 250:         MapGuideApi.MgInitializeWebTier(szMGWebTier)
 251:         Dim siteConnection As New MgSiteConnection()
 252:         siteConnection.Open(New MgUserInformation(szMGUser, szMGPass))
 253:         Return siteConnection
 254:     End Function
 255:  
 256:     ''' <summary>
 257:     ''' Converts MgReader to XMLDocument
 258:     ''' </summary>
 259:     ''' <param name="byteReader">Loaded MgByteReader</param>
 260:     ''' <returns>Loaded XMLDocument</returns>
 261:     ''' <remarks></remarks>
 262:     Public Shared Function ConvertMgReaderXml(ByVal byteReader As MgByteReader) As XmlDocument
 263:         Dim szXML As String
 264:         Try
 265:             szXML = byteReader.ToString
 266:         Catch ex As Exception
 267:             Throw ex
 268:         End Try
 269:         Dim nByteCount As Integer
 270:         Dim arrByte(szXML.Length) As Byte
 271:         Try
 272:             nByteCount = Encoding.UTF8.GetBytes(szXML, 0, szXML.Length, arrByte, 0)
 273:         Catch ex As Exception
 274:             Throw ex
 275:         End Try
 276:  
 277:         Dim memStream As New IO.MemoryStream(arrByte)
 278:         Dim retDoc As New XmlDocument
 279:         retDoc.PreserveWhitespace = True
 280:         Try
 281:             retDoc.Load(memStream)
 282:         Catch ex As Exception
 283:             memStream.Close()
 284:             memStream.Dispose()
 285:             Throw ex
 286:         End Try
 287:         memStream.Close()
 288:         memStream.Dispose()
 289:         Return retDoc
 290:     End Function
 291:  
 292:     ''' <summary>
 293:     ''' Gets a ResourceList for each item in the specified repository folder.
 294:     ''' </summary>
 295:     ''' <param name="resSvc">The opened resource server connection</param>
 296:     ''' <param name="resId">The MgResourceId of the folder we want to enumerate</param>
 297:     ''' <param name="nDepth">The folder depth to enumerate.  From the Mapguide Web API Reference:
 298:     ''' (int) Recursion depth, relative to the specified resource.
 299:     '''* If the resource is a document, depth must be set to 0.
 300:     '''* If the resource is a folder:
 301:     '''      o If the depth is equal to 0, only information about the specified folder is returned.
 302:     '''      o If the depth is greater than 0, information about the folder and its descendants up to the specified depth are returned.
 303:     '''* If the depth is -1, information about the folder and all its descendants is returned.
 304:     ''' </param>
 305:     ''' <param name="szType">Again from the Mapguide Web API Reference:
 306:     '''     (String/string) Type of the resource to be enumerated. (Case sensitive.) See MgResourceType  for valid types. If the type is a folder, 
 307:     '''     you must include the trailing slash.
 308:     '''     Or, this can be set to null, in which case information about all resource types is returned
 309:     ''' </param>
 310:     ''' <returns>OSGeo.Mapguide.Objects.ResourceList of resource entities</returns>
 311:     ''' <remarks></remarks>
 312:     Public Shared Function GetAllResources(ByRef resSvc As MgResourceService, ByVal resId As MgResourceIdentifier, ByVal nDepth As Integer, ByVal szType As String) As OSGeo.MapGuide.Objects.ResourceList
 313:         Dim retDoc As XmlDocument
 314:         retDoc = ConvertMgReaderXml(resSvc.EnumerateResources(resId, nDepth, szType))
 315:  
 316:         Dim resourceList As New OSGeo.MapGuide.Objects.ResourceList
 317:         resourceList = OSGeo.MapGuide.Objects.ResourceList.Parse(retDoc.OuterXml)
 318:         Return resourceList
 319:     End Function
 320: End Class

If you have any questions or comments – feel free to let me know.

Older Posts »

Powered by WordPress