Kristian Kristensen’s Blog


The Simple Way to Generate One File MSDN Style Documentation for Your .NET Projects

Posted in Code,Microsoft by Kristian Kristensen on the June 10th, 2011

I was recently tasked with generating code documentation. The last time I had to do that I used NDoc and the XML Comments that the C# compiler (csc.exe) spits out. Turns out that NDoc is no longer, or at least it’s not being maintained. Instead the new kid on the block is Sandcastle.
It might be my memory failing, but I seem to remember that setting up NDoc to generate MSDN style documentation was pretty easy. My initial foray into using Sandcastle was not. This post describes a super simple way to generate MSDN style documentation that’s contained in a single CHM file.

We’ll need some software. So go ahead and download and install the following:

Optional:

  • GhostDoc – http://submain.com/products/ghostdoc.aspx
    Not required, but it makes it super easy to generate XML documentation from within Visual Studio. It’ll even auto generate some of the text. The free version is fine, but obviously the paid version includes more features.

With all of the software installed and in place, it’s time to generate some documentation.

  • Open Sandcastle Help File Builder GUI and start a new project.
  • Right click Documentation Sources on the right and select “Add Documentation Source”.
  • Find and select your solution file (*.sln).
  • Select “HtmlHelp1″ under HelpFileFormat under the “Build”-category.
  • Fill out whatever other properties you want. HelpTitle and HtmlHelpName are obviously good for putting in the name of your project. The “Show Missing Tags”-category is good for fine tuning what’s added if you haven’t explicityly documented everything.
  • Hit CTRL+SHIFT+B or select “Build Project” from the “Documentation”-menu.
  • Wait.
  • You should now have a .chm file in your output folder.

Remember if your distribute the CHM file by putting it on the internet and allowing people to download that they need to Unblock the file first, before opening it. Otherwise all of the links inside will fail. You can see my post on X.509 Certificates and Downloads Via Internet Explorer for a description of the troubles that can occur when downloading files and they’re marked as being unsafe.

  • If you like my writing you should subscribe to my RSS feed.

    JSON Proxy Using IIS Reverse Proxy for Fun and Profit

    Posted in Code,PhoneGap,Sencha Touch by Kristian Kristensen on the June 7th, 2011

    Developing mobile applications using Sencha Touch that will be packaged up using PhoneGap to run as a “native” app on a phone can be a bit of a pain. Especially if you’re accessing some kind of API. Because of restrictions in the browser, you’re not allowed to do cross site requests, meaning it’s difficult to call external API’s during development. You’re likely to run your new shiny mobile app from a file on your hard drive or served up by a locally running web server. But the API’s you need to access are probably running on a another external server. Hitting that API will give you a sad message from Chrome, because of the “Same Origin Policy”. Safari will just return nothing, and ignore you. IE9 and Firefox are not even options, because they don’t run WebKit. You can of course do all of your development in PhoneGap, deploying to an emulator or a real device and always test on that. But it adds quite a bit of time to the feedback loop and for prototyping it’s especially nice to have the fast feedback loop afforded by the browser, the console and the inspector. So how do we get around this annoyance. One way is to use JSON-P and the ScriptTagProxy. Another is to utilize a reverse proxy server, which is what I’ll describe in this post.

    I’m developing on Windows 7, so this is a description on how to set it up using IIS. This guide on the IIS.net website explains things in more detail. If you’re running on Mac or Linux you could setup nginx, Apache or another web server. Most web server software include proxy rewrite and reverse proxy capabilities.

    Before we get started here’s a quick and simple diagram of what we’re trying to achieve:

    Browser < => Local Web Server (IIS) Proxy To => External Server with API
    

    First you’ll want to install the Application Request Routing module. This module works with the URL Rewrite module to proxy requests back and forth between your web server and some other back end server. Next step is to enable the ARR module on your IIS Root.

    Then on your web site that hosts your mobile application code (basically just a virtual directory to your web root of your Sencha Touch application) you want to configure the URL Rewrite module. There are a couple of options for doing this, one is through the IIS Management GUI, the other is by adding the appropriate configuration in your web.config file. I’ll list the configuration settings in the following, but you can just as well set this up using the GUI and the guide. Another options is to copy in the following configuration settings, and then tinker with it using the GUI afterwards. The IIS Manager GUI is basically a nice way of manipulating web.config files.

    If your virtual directory doesn’t have a web.config (it probably doesn’t since it’s serving up plain HTML and JS) create a new file called web.config and fill in the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    </configuration>
    

    Then add the following in between the configuration-tags, so your entire file looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    <system.webServer>
    <rewrite>
    <rules>
    <rule name="Proxy To External server" stopProcessing="true">
        <match url="^services/(.*)" />
        <conditions>
        </conditions>
        <action type="Rewrite" url="http://my-external-server.com/{R:0}" logRewrittenUrl="false" />
    </rule>
    </rules>
       <outboundRules>
       <rule name="Add Application prefix" preCondition="IsHTML">
            <match filterByTags="A" pattern="^/(.*)" />
            <conditions>
                 <add input="{URL}" pattern="^/(appName)/.*" />
            </conditions>
            <action type="Rewrite" value="/{C:1}/{R:1}" />
       </rule>
       <preConditions>
       <preCondition name="IsHTML">
            <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
       </preCondition>
       </preConditions>
     </outboundRules>
    </rewrite>
    <urlCompression doStaticCompression="false" />
    </system.webServer>
    </configuration>
    

    This configuration says to rewrite all requests coming into the virtual directory at http://localhost/appName/services/ to http://my-external-server.com/services/. The outbound rule looks at the returned HTML and rewrites that too, so links and hrefs will continue to work. If you don’t do this step, links won’t be rewritten and when you follow them you’ll get an error because the links point to the server you’re trying to mask.

    With this in place you can configure your Sencha Touch data classes to use http://localhost/appName/services/ as the server prefix, and service calls will be proxied back and forth to your external data server. To make it easier to transition from development to production, wrap the server prefix in a configuration object.

    I’ve found this proces to be of tremendous value when developing. It’s so much easier to debug things when they run in the browser and you can use the full browser stack.

    One thing I’ve found is that sometimes IIS will barf and throw an internal server error related to request compression and GZip’ping. I’ve disabled Static Compression in the hope that that would help, which it does. The error still shows up though. I’ve found that a quick “iisreset” does the trick and puts everything back on the track. This minor annoyance is worth it compared to the added benefit of running everything in the browser and skipping an emulator.

  • If you like my writing you should subscribe to my RSS feed.

    Creating Podio Voicemail Using Tropo, Podio and PHP

    Posted in Code,Misc,Podio,Tropo by Kristian Kristensen on the June 3rd, 2011

    On Wednesday June 1st I went to the Podio World Tour NYC App Camp. I didn’t really plan on making anything, I mainly showed up to check it out and say hello to the Podio peeps. However, I got into a small chat with @fabianmu and @froda about how to augment Podio, so you could call a phone number and have a message be posted into Podio. I thought: that’s pretty easy! I’ll just whip up Tropo and add some PHP to glue it all together and I’ll be golden. Basically yes, however it took a bit longer than the time I had that evening. This post explains what I did and how it works.

    Scenario

    You have a phone number that anyone can call. Once connected the user is asked to leave a voicemail for you. The recording is transcribed to text and both the recorded audio file and the text is uploaded to special app on Podio. That way you have a central voice mailbox for your company/organization integrated into your Podio space.

    Podio Setup

    Here’s how it looks in Podio.

    When a new message has been placed in the voice mailbox, it’ll be included in the Activity Stream of the space. In the top navigation bar we see the “Calls”-app which holds all of the individual calls.

    Podio - Activity Stream

    Clicking a single item reveals the following picture. Here we see all of the details of the call including a transcription of the voice mail.
    Podio - Single Item

    The “Calls”-app is simple and was configured using the Podio App Builder. It just has a single text field for the transcription, as well as the default title. The audio file is attached using the standard attachment feature.
    Podio - New Call

    Tropo Setup

    In this scenario Podio works as a receiver of information and hence we’ll use the API to add this information. In order to record the I used Tropo which is a service like Twilio. It allows you to create voice and text message communication solutions and have your own code executed when certain things happen. Here we want something to happen when a user calls us up over the phone. The following image shows the configuration of my Podio Tropo app.

    Podio - Tropo

    I utilize the Hosted option on Tropo, and have assigned a local US number to it. This means that whenever someone calls this number, the code in the hosted file Podio.rb will be executed. That file contains the following code.

    say "Welcome to the Podio Voice Mail."
    
    callerID = $currentCall.callerID
    sessionId = $currentCall.sessionId
    
    record "Please leave a voicemail for us. When you are finished recording, press the pound key.", {
        :beep => true,
        :maxTime => 60,
        :terminator => '#',
        :recordURI => "http://server.com/hook.php?callerId=" + callerID + "&sessionId=" + sessionId,
        :transcriptionOutURI => "http://server.com/hook.php?callerId=" + callerID + "&sessionId=" + sessionId,
        :transcriptionID => sessionId
        }
    say "Thank you!"
    hangup
    
    • First we greet the user.
    • Then we extract some information about the call, caller id is the number the user is calling from, session id is an internal id we can use as an identifier.
    • We ask the user to leave a voicemail for us, and press # when done. When he/she has done this we ask Tropo to post the recording to a server and passing along some information in the query string. We also request transcription to be done, and the result of that should be posted to the specified URL. Again we utilize the query string to pass some information.
    • Then we thank the user and finally hangup.

    Custom PHP Glue

    The receiving code running on a server is where we glue the output of Tropo together with Podio. I had some trouble getting PEAR to work when I first hacked on it. However, googling around helped me get it up and running. The trick to install the required PEAR packages for the Podio PHP helper was to run

    pear install HTTP_Request2-beta
    

    Also I had to modify my “open_basedir” to allow PHP to include files from the PEAR directory. Once that was done, the Podio PHP library worked like a charm.

    The PHP script that receives data from Tropo and uploads it to Podio has a number of elements to it. First we setup the required information to access Podio:

    <?php
    require_once('podio-php/PodioAPI.php');
    
    $client_id = 'YOUR_CLIENT_ID';
    $client_secret = 'YOUR_API_SECRET';
    
    $oauth = PodioOAuth::instance();
    $baseAPI = PodioBaseAPI::instance($client_id, $client_secret);
    
    $baseAPI->setLogHandler('file', 'podio_log.log', 'podio');
    
    //log base info
    $baseAPI->log(serialize($_GET));
    
    $file_name = 'audio-' . $_GET['sessionId'] . '.wav';
    $target_path = '/var/www/' . $file_name;
    

    We set up the basic API Client information. You can create this by going to the API Keys page on your profile. Also we setup a log file to make it easier to see what’s going on. We setup the file name and the target path, which will be where the audio file will be stored locally. We use the session identifier as part of the name to be able to retrieve it later, when the transcription result comes in.

    To save the audio file received from Tropo the following code goes into effect:

    if (is_uploaded_file($_FILES['filename']['tmp_name'])) {
      if(move_uploaded_file($_FILES['filename']['tmp_name'], $target_path)) {
              $baseAPI->log("$target_path [{$_FILES['filename']['size']} bytes] was saved");
      } else {
             $baseAPI->log("$target_path could not be saved.");
      }
    }
    

    Here we utilize the variables set up previously.

    Once the transcription result is posted to our PHP code, we execute the following.

    // Obtain access token
    $username = 'YOUR_USER_ID';
    $password = 'YOUR_PASSWORD';
    $oauth->getAccessToken('password', array('username' => $username, 'password' => $password));
    
    $api = new PodioAPI();
    
    $transcription_input = @file_get_contents('php://input');
        $obj = json_decode($transcription_input);
    
        $baseAPI->log('Transcription input: ' . $transcription_input);
    
    $file = $api->api->upload($target_path, $file_name);
    

    First we log in to the Podio API and get an object reference to it. Then we read the posted JSON transcription result from Tropo into a temporary variable and JSON decode it. We upload the audio file posted previously and hold on to the reference returned from Podio.

    Next is the actual code that posts the item into the “Calls”-app in Podio. @fabianmu’s shodio project was of great help in figuring out how to construct the field and value arrays.

    $app_id = YOUR_APP_ID;
    
    //create fields array
    $newItem = array();
    $newItem['appId'] = $app_id;
    $newItem['external_id'] = $_GET['sessionId'];
    $newItem['tags'] = array();
    
    //Title field
    $newField = array();
    $newField['field_id'] = 1817081;
    $newField['values'][]['value'] = 'New voicemail from ' . $_GET['callerId'];
    $newItem['fields'][] = $newField;
    
    //Transcription field
    $newField = array();
    $newField['field_id'] = 1817083;
    $newField['values'][]['value'] = $transcription_input;
    $newItem['fields'][] = $newField;
    
    $item = $api->item->create($app_id, $newItem['fields'], array((int)$file['result']['file_id']), $newItem['tags'], $newItem['external_id']);
    
    $baseAPI->log("new item posted to podio: " . serialize($item));
    

    We basically construct the required fields, putting in “New voice mail from $CALLER_ID” and adding the transcribed result to the transcription field. Then we create a new item for our app identified by $appId, associate the file we uploaded earlier to the item and put in the session identifier from Tropo as the external_id. To verify that something happens, we log out the returned item from Podio.

    Conclusion

    Tinkering with Podio’s API was really fun. As always there was a bit of a learning curve in getting the API helpers up and running. Getting the right versions of PEAR and related libraries, and making sure that everything connects together took most of the time. Also figuring out where and how Tropo posts the audio file and the transcription result, took a bit of tinkering.
    It’s amazing how quickly you can built something with these new API’s and services out there. Voice enabling an app in less than a 100 lines of code is pretty neat.

  • If you like my writing you should subscribe to my RSS feed.

    Dates With a Sencha Touch Data Model and a WCF JSON Service

    Posted in Sencha Touch,WCF by Kristian Kristensen on the June 3rd, 2011

    I’ve been developing a Sencha Touch Mobile app recently, that interface with a WCF REST service exposing data via JSON. One of the issues I faced was parsing the dates returned from the service into a date type in the Sencha Touch Data Model. This post explains one way to do that.

    Say we have a simple model that only holds an id and a date:

    Ext.regModel("MyModel", {
      fields : [
        'id',
        {name : 'MyDate', type : 'date'},
      ]
    });
    

    When data is read into this model using a Proxy from a WCF REST JSON service, the MyDate column will just hold the string representation of the data such as “/Date(1238606590509+0800)/”, ie. it won’t be parsed. The trick to overcome this is to utilize the “convert” property that you can set on a field. This allows you to call out to a helper function every time a value will be set on the model for that field.
    Now our model looks like this:

    Ext.regModel("MyModel", {
      fields : [
        'id',
        {name : 'MyDate', type : 'date', convert : toDateFromJSON},
      ]
    });
    

    We need to define our converter function;

    function toDateFromJSON(v, record) {
      return Date.parseDate(v, "M$");
    }
    

    In this converter function we utilize the built in Date object. When giving it the format string “M$” it will parse Microsoft Serialized AJAX dates which is what’s used with WCF, REST and the JSON formatter OOB.

    Now our model will have the correct datatype for the MyDate property, which will allow us to call useful functions on it such as format.

  • If you like my writing you should subscribe to my RSS feed.