Wednesday, September 17, 2008

Flex and .Net

I'm currently investing time in learning how to connect a Flex RIA to a .Net server. Having worked for many years on web applications in the finance and banking sector I am well acquainted with the trials associated with rendering forms and implementing user experience consistently on a variety of modern and vintage web browsers. The ability to design and code for a single runtime environment has strong appeal. The stumbling blocks for me have been a loathing for Flash-based advertising and poorly constructed Flash-based websites. Actually my loyalty to Firefox is due in part to the ability to selectively enable Flash via the FlashBlock extension. And did I mention that I also dislike Adobe Reader? How can Adobe turn something so simple into an unwieldy bohemiath.


However the biggest stumbling block is the lack of detail surrounding Flash/AIR session handling and caching. This is something that is well understood in browsers; an online banking site will typically store a session cookie in your browser cache and you can feel confident that cookie will be erased when the session is ended. I believe this isn't necessarily the case for Flash although I can't just now place my hands on the particular URL where this issue was being discussed. At the time it was enough to shelve my interest and it's an issue I need to revisit.


So there are a number of ways to connect from an AIR application to a server application. An obvious one is via Web services. This has the enormous benefit on the server side that having written and published your Web service it is now available for any client-side or peer-to-peer technology that knows how to speak your particular flavour of Web service (SOAP/REST). A disadvantage of even a well-designed SOAP Web service can be the amount of XML data being shipped to the client. This is going to impact the responsiveness of an application even over a broadband connection. For AIR the alternative is to use Flash Remoting, the benefits of which according to this Mark Piller tutorial "include significant performance improvements, reduced development costs, and a more natural client/server integration". At this stage I'm just going to accept those claims, I don't have any good reason to dispute them.


Using Mark's tutorial turned out to be a reasonable place to start. There is a commercial Flash Remoting product but Mark's company gives away the previously commercial WebOrb Flash Remoting application. The tutorial had one unfortunate omission that had me scratching my head, I was consistently getting an error message “Destination 'GenericDestination' either does not exist or the destination has no channels defined (and the application does not define any default channels.)”. I don't know if this occurred because I'm using Flex Builder 3 rather than version 2 as in Mark's tutorial. I found the resolution on one of the forum pages. I needed to provide the additional Flex Builder compiler argument -services "services-config.xml" and copy the services-config.xml, remoting-config.xml, and data-management.xml from C:\inetpub\wwwroot\weborb30\WEB-INF\flex into the src directory of my Flex Builder project.


The need I have at the moment is to feel confident I can replicate this quickly in order to pitch for some work. That work entails integrating a Flash/Flex application with .Net server-side and some form of repository, all in a package I can distribute to a hosting environment. Trying to tie those strings together is where the tutorial unravels. GenericDestination is not something I want to use for a production environment, it allows access to every deployed assembly in the .Net application. The tutorial even indicates that it shouldn't be used in a production environment. On the Web what is easy is often used by default, particularly by inexperienced developers. To identify the alternative configuration I need to dig deeper, I'm sure many wouldn't bother. This is a peeve, if you're going to go to the trouble of writing a tutorial, show me how to do the job correctly. In this case the easy way has serious security implications that may be ignored by developers who just want to get something out there.


So now I want to start filling in the gaps. The above-mentioned GenericDestination needs to be replaced with something appropriate. I need to understand what is required to deploy my application into a hosted environment. I need to integrate my application with some form of repository and I'm leaning towards NHibernate largely because I had some recent exposure to its Java forebear Hibernate and I'm curious.

Wednesday, September 3, 2008

Installing Subversion on Leopard

Having previously installed subversion on Linux without issue ($ sudo yum install subversion and $ sudo chkconfig --add svnserve) I was expecting a similarly happy experience with Mac OS X 10.5. Perhaps I wasn't paying as much attention the second time around which contributed to my woes. The various instructions I used as reference all got me part of the way for which I'm grateful.


As an aside, I'm also partway through the extraordinary Flow: The Psychology of Optimal Experience. In this case installing and configuring subversion was definitely not a flow activity for me. One of the precursors to achieving flow is being able to concentrate. Trying to find useful information on the Internet can be extremely frustrating. I know the information I'm looking for, I drop some search terms into Google, middle-click some likely links to open in new tabs, and then wade through the tabs looking for the good stuff. Effectively I've just broken my concentration to spend unproductive time looking for the answer to a question that can be difficult to phrase without trawling all manner of dead herrings (so to speak). Think about how good the MSDN documentation is and how easy it is to find not only the API you're looking for but also example code. Think about the code completion features in Visual Studio. These all contribute to getting you into a state of flow and keeping you there.


Getting back to my skirmish with subversion, here's how it all panned out. The first step is to install subversion (I know there are options that don't include compiling from source but I like to see the machinery working):



$ mkdir subversion
$ cd subversion
$ curl -O http://subversion.tigris.org/downloads/subversion-1.5.1.tar.gz
$ curl -O http://subversion.tigris.org/downloads/subversion-deps-1.5.1.tar.gz
$ # that's the letter O btw, not a number.
$ tar xzf subversion-1.5.1.tar.gz
$ tar xzf subversion-deps-1.5.1.tar.gz
$ cd subversion-1.5.1/zlib
$ ./configure
$ sudo make install
$ cd ..
$ ./configure --prefix=/usr/local --with-ssl --with-zlib=/usr/local
$ sudo make install

Actually I was in something of a hurry and some of the suggested options were causing the configure step to fail. The instructions I was following didn't include the step to build and install zlib, and didn't include specifying the location of the library. Configure would fail when trying to locate the library and googling turned up a lot of information but not much of it useful. YMMV.


So that takes care of $ sudo yum install subversion. The next step is to get subversion to load at boot. On Mac OS X this is handled by launchd. I've previously written a launchd plist for PostgreSQL under OS X 10.4 where the data was stored on a firewire-attached RAID. I have a strong recollection that it was a PITA trying to get it to wait for the RAID to be initialised before starting postgres. I went back to the freyside and used his sample plist. It was pretty close, but it didn't specify a username for running subversion. It turns out that there already exists a subversion account on Leopard, _svn. The modified /Library/LaunchDaemons/subversion.svnserve.plist is below. And the new service can be initialised without rebooting by $ sudo launchctl load /Library/LaunchDaemons/subversion.svnserve.plist.



<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Disabled</key>
    <false />
    <key>UserName</key>
    <string>_svn</string>
    <key>Label</key>
    <string>subversion.svnserve</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/bin/svnserve</string>
      <string>--inetd</string>
      <string>--root=/Users/dave/develop/source</string>
    </array>
    <key>ServiceDescription</key>
    <string>Subversion Standalone Server</string>
    <key>Sockets</key>
    <dict>
      <key>Listeners</key>
      <array>
        <dict>
          <key>SockFamily</key>
          <string>IPv4</string>
          <key>SockServiceName</key>
          <string>svn</string>
          <key>SockType</key>
          <string>stream</string>
        </dict>
        <dict>
          <key>SockFamily</key>
          <string>IPv6</string>
          <key>SockServiceName</key>
          <string>svn</string>
          <key>SockType</key>
          <string>stream</string>
        </dict>
      </array>
    </dict>
    <key>inetdCompatibility</key>
    <dict>
      <key>Wait</key>
      <false />
    </dict>
  </dict>
</plist>

Nearly there. I'm using TortoiseSVN in Parallels to access my subversion repository (which is really not going to work if I use BootCamp). I created my repository via



$ svnadmin create /Users/dave/develop/source/

Trying to access the repository using the TortoiseSVN Repo-browser from Parallels resulted in the error expected FS format '2'; found format '3'. Turns out subversion 1.5 has a new repository format to support some new features. For some reason TortoiseSVN (1.5.3, Build 13783 - 32 Bit , 2008/08/30 20:59:46) on my system didn't want to talk to the new format. At this stage my repository is for personal use and I'm really OK with using the older format. I deleted my repository and started over. Note also that the _svn account needs to be able to write to the repository, it seemed reasonable to make _svn the owner of the repository:



$ svnadmin create --pre-1.5-compatible ~/develop/source/
$ sudo chown -R _svn ~/develop/source

Now to create the root for my c# code.



$ svn mkdir svn://localhost/csharp --username dave -m "c# source"
svn: Authorization failed

Duh, so after uncommenting the line # password-db = passwd in ~/develop/source/conf/svnserve.conf and adding an appropriate entry to ~/develop/source/conf/passwd my subversion repository is alive and I can access it from Parallels using TortoiseSVN.