# Wednesday, September 03, 2008

Another day, another fun error message.  Thanks to all the fun I've been having with - I've given up and created a new virtual machine with XP Pro to run Visual Studio in.   So I grab the latest revision from source control and load the solution in Visual Studio.  Boom.  Sytem.Runtime.InteropServices.ComException.  That's it. No more details.  This is one of those errors where it could be just about anything.  A gives way too many results.

So I'm going to add one more search result on this error message.  After much muckery - I've resolved my instance of the problem.  The background is simple.  I have an ASP.NET web application with a few DLL projects and a deployment project.  As stated, I've created a new install of Windows XP.  First ensure that you have the add-on installed.  That can also cause this error (in some cases).

The key thing in this case was the lack of IIS on the machine.  On my primary development machine (the one where Oracle is a massive pain) I do have IIS installed, and the last time I ran this project from that machine - Oracle was working OK with the data access hack.  But apparently something has changed on that box and now I'm getting the evil "Oracle client and networking components were not found." error.  So I gave up.

First obvious work around is to install IIS.  I'm sick of messing around today, and just want to work.  So the quicker solution is to enable the built in development web server.  This can be accomplished by right clicking the unloaded project in the Visual Studio solution explorer and choosing "Edit <projectname.whateverlanguateyouuseproj>".  This will bring up the XML view of the project.  Find the ProjectExtensions section of the config and change UseIIS to be False.  Setting this up could also prevent problems when you have a larger, or more dynamic team accessing the project.

   1: <ProjectExtensions>
   2:     <VisualStudio>
   3:       <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
   4:         <WebProjectProperties>
   5:           <UseIIS>False</UseIIS>
   6:           <AutoAssignPort>False</AutoAssignPort>
   7:           <DevelopmentServerPort>4088</DevelopmentServerPort>
   8:           <DevelopmentServerVPath>/webrade</DevelopmentServerVPath>
   9:           <IISUrl>http://localhost/WebRADE32</IISUrl>
  10:           <NTLMAuthentication>False</NTLMAuthentication>
  11:           <UseCustomServer>False</UseCustomServer>
  12:           <CustomServerUrl>
  13:           </CustomServerUrl>
  14:           <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
  15:         </WebProjectProperties>
  16:       </FlavorProperties>
  17:     </VisualStudio>
  18:   </ProjectExtensions>

 

Reload the project, and it should load now.

P.S. Oracle, please please please release something for Vista x64 and ODAC/ODP.  Even an alpha.  I promise I will test on an x86 machine before I release..

Technorati Tags: ,
Wednesday, September 03, 2008 3:04:14 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Wednesday, July 30, 2008

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!

  Technorati Profile
Wednesday, July 30, 2008 3:22:27 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Tuesday, July 29, 2008

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 

Tuesday, July 29, 2008 10:37:46 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Friday, June 13, 2008

recently released a 64 bit native built of the server.  I'm on a real x64 kick lately and really enjoy not seeing *32 beside my processes in task manager.  Vault is one of the best source control providers out there, and you cannot beat the price either.  It is core to my professional life.  Next to Visual Studio - it is one of the most important pieces of software I use. So, did a quick backup of my databases, un-installed the old server and installed the shiny new x64 code.  Problems!

First off, my server was running IIS in 32 bit mode.  This was required to run the previous releases of Vault.  Once the install was complete, I started a dos window and set IIS back to 64 bit:

cscript.exe C:\Inetpub\AdminScripts\adsutil.vbs set W3SVC/AppPools/Enable32BitAppOnWin64 0

Then I ran an iisreset.

When I fired up my browser to check the vault service, there was a problem.  All it would display was "Service Unavailable".  At this point, even html files were not being served out.  Did a search on the Sourcegear forums and couldn't find anything.  It's been a long week and I was not firing on all cylinders - so I called up the support team.  (Good thing I renewed my maintenance, oh, this morning =D).  At this point Beth from SourceGear and I brainstormed through the situation and came to the following conclusions:

I was the first customer to call with x64 problems.  Yay for being first!

In IIS Manager, the application pool was disabled.  A check of the event logs showed the following information:

Source: W3SVC-WP

Event ID: 2268

Could not load all ISAPI filters for site/service.  Therefore startup aborted.

This prompted a check the web service extensions.  Sure enough, there was a web service extension there configured for ASP.NET pointing to the 32 Bit assemblies.  I prohibited this extension, and added a new one pointing to the 64 bit aspnet_isapi.dll.  Re-enable the application pool and load a page in the browser - still nothing.

Finally - the last step needed to get everything serving properly was to run the following from the x64 framework folder:

c:\windows\microsoft.net\framework64\v2.0.50727\aspnet_regiis -I -enable

So in summary the following steps should get your Vault server upgraded and running in native x64.  Bear in mind, my server is ONLY running Vault and these steps will break ASP.NET 1.1 applications (and lower) and possibly other code you might have running on the server.

   1: Backup SGVault and SGMaster databases (did I even need to include this?)
   2: Un-install the 32 bit Vault server
   3: Install the 64 bit Vault server
   4: Run cscript.exe C:\Inetpub\AdminScripts\adsutil.vbs set W3SVC/AppPools/Enable32BitAppOnWin64 0
   5: Run c:\windows\microsoft.net\framework64\v2.0.50727\aspnet_regiis -I -enable
   6: Start IIS Manager. 
   7: Double check the vault virtual directories to ensure the ASP.NET version is set to v2.0
   8: Prohibit the ASP.Net 32 bit isapi web service extension
   9: Add the ASP.Net 64 bit isapi web service extension
  10: run IISReset.exe

 

mmmm x64 goodness.  Thanks again to Beth for helping me work through this =)

ASP.NET | IIS 6 | x64
Friday, June 13, 2008 3:11:30 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |   |  Trackback
# Wednesday, May 21, 2008

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.