Infinity Lab Notes

Infinity Lab Notes http://labs.blackbaud.com
RSS Feed
Infinity Platform - Mobility
Wednesday, December 09, 2009
We have been working very hard on the mobility support in the Infinity platform.  I thought it might be a good idea to post on where we are at, and outline our high level mobile strategy.

I just posted a short 5 minute sneak peak of the iPhone integration coming in the Q1 release of Blackbaud Enterprise CRM, so if you have a few minutes, please watch the screen cast.

Our basic goals for the mobile platform were:

Extend reach of key functionality to a broad range of mobile devices.  

We have built the platform in a way that does not have any affinity for a particular mobile platform or OS.  iPhone is baked, and Android is on the way.  I suspect you'll see support for RIM and Windows mobile soon as well ;)

Leverage existing core features and information assets

There are tons of useful features and interesting sets of data that are perfect for mobile access.  Query, KPI's, geocoded data and more.  Getting our customers investment in their existing information assets is an important initial step.  Soon we will begin to branch out to applications that are unique to the mobile platform, but first it is all about extending reach.

Integrate with native device functionality (GPS, Camera, etc.)

Where possible the mobile platform will scale to the unique capabilities of the device.  I am excited about the future here, in particular we have some cool ideas around how we can help our customers go in the area of user-generated content.  I'm still trying to think of a good use case for leveraging the accelerometer :)

UI targeted to form factor

Even though we are cross-platform in a mobile sense, Blackbaud mobile applications embrace the native UI and look and feel of the device they are running on.


More on this stuff soon!

Shaun
Infinity API in the wild
Tuesday, April 21, 2009
 
A core tenet of Blackbaud's Infinity platform is embracing an open, 3rd party developer ecosystem.  Thus, I was excited to see a 3rd party developer digging into our SDK and building something cool.  Even better, free! 
 
Enter David Zeidman, of Zeidman Development.  Using the Infinity Software Development Kit (SDK), Mr. Zeidman built an interesting integration between the special events feature and Google Calendar.  The component makes use of the Infinity Web Services API, Infinity LINQ integration (code name "metal") and integrates directly into the Blackbaud Enterprise CRM user experience.
 
This same API and technology platform powers the forthcoming Raiser's Edge 8.  With Javascript APIs, a RESTful API stack, and a traditional SOAP API, the developer will have full access to over 9,500 individual features and entities in the system. 
 
 
I can't wait until a large developer community can be unleashed on the open API.  Stay tuned!
 
Shaun Sullivan
CTO
Blackbaud, Inc.  
JavaScript IntelliSense From WCF Data Contracts
Tuesday, February 24, 2009
With the advent of Microsoft's Windows Communication Foundation (WCF) technology, creating REST services on the .NET platform has become a very attractive prospect for many developers.  WCF's native support for JSON serialization combined with URI templates for creating resource-based URLs makes creating RESTful web services even more attractive for developers looking to use WCF to build Ajax-based web applications.  In fact, the Nimbus project demonstrated at Blackbaud's 2008 Conference for Nonprofits is largely built on WCF web services, along with a JavaScript library that makes it easy to communicate with those web services.
 
One major hurdle for many developers writing WCF-based Ajax applications (or even writing JavaScript in general) is the lack of familiar tools with which to build these applications.  Until recently, Microsoft Visual Studio has not supported JavaScript with conveniences like IntelliSense which .NET developers have become accustomed to.  Fortunately Microsoft has done a lot in the way of adding IntelliSense support with Visual Studio 2008 SP1, and popular JavaScript libraries like jQuery are jumping on board to support IntelliSense in Visual Studio.
 
If you're not familiar with how JavaScript IntelliSense works in Visual Studio, here's a quick overview.  JavaScript functions are documented using XML comments, much like XML code comments for Visual Basic.NET and C#.  These comments include a summary of the function, the parameters and their types, and a description of what the function returns.  JavaScript constructors may contain more information, such as "instance" fields that are accessible off of objects created from the constructor.  At design time, Visual Studio reads these comments from within the JavaScript functions and builds the IntelliSense for those functions.  Full documentation for how JavaScript XML code comments work can be found here, which is suggested reading before delving into the rest of this article.
 
So what does this have to do with WCF?  WCF web services work by taking an object on the server and serializing that object to either JSON or XML (we'll only be discussing JSON in this article as it is the format that most easily lends itself to JavaScript programming), then sending that payload down to the client.  WCF knows how to turn these objects into JSON by looking at the DataContract and DataMember attributes used to mark up the class.  Once a JavaScript method has received a JSON payload, it can be turned into a JavaScript object, either by calling eval() on it or by using any of the popular JSON parsers available on the web. 
 
When using certain techniques in ASP.NET, such as using an ASP ScriptManager control and ScriptMethods, Visual Studio can generate IntelliSense for the data contract classes.  But what if you are building a re-usable library like Nimbus which is designed to be used within any web application, including applications not created with ASP.NET or even hosted on a Windows server?  Not only would it be ideal to get IntelliSense on your data contracts while developing your library, but it would also be beneficial to other application developers using your library to get that same experience when building their own applications.
 
To achieve this, I've created a utility that will generate a JavaScript IntelliSense file from data contract classes.  Given a .NET assembly, the utility will find all classes with the DataContract attribute, look at its DataMember properties and generate corresponding JavaScript file, complete with XML comments that include the data type of each property and a description if specified.  Here's how it works:
 
Data Contract Classes
 
First, make sure your data contract classes are marked up properly.  Your data contract class should have a DataContract attribute, and each property to be serialized should have a DataMember attribute.  You should also add a System.ComponentModel.Description attribute to the classes and properties so the utility can use the description when creating the JavaScript IntelliSense file.
 
In this example, I have three data contract classes: Individual, Address, and PhoneNumber.  Each Individual has an ID, FirstName, LastName, Gender, MailingAddress, and a collection of PhoneNumbers.  Here's an example of how the PhoneNumber class is marked up (Individual and Address have similar attributes): 
 
Imports System.ComponentModel
Imports System.Runtime.Serialization

<DataContract(Name:=
"phoneNumber")> _
<Description(
"An individual's phone number.")> _
Public Class PhoneNumber

   
Private _number As String
   
<DataMember(Name:="number")> _
    <Description(
"The formatted phone number.")> _
   
Public Property Number() As String
        Get
            Return
_number
       
End Get
        Set
(ByVal value As String)
            _number = value
       
End Set
    End Property

End Class
 
 
Run the Utility
 
Once you've written your data contract classes and have compiled your project, it's time to run the utility.  Download and run DataContractJSGenerator.exe or compile and run the included source code.  You should see this window:
 
 
First, browse to the assembly containing your data contracts.  Next, choose a JavaScript namespace that will contain your data contract objects (I'll be using BB.contracts for this example).  Choosing a namespace will keep your data contract objects from clashing with other global variables.  The "Include 'IntelliSense-only' warnings in generated code" option will include a warning in the summary of each object telling the user not to instantiate them, since this file will only be used for Visual Studio IntelliSense and will not be included in the application at runtime.  Finally, you may choose to save the file to disk once the JavaScript is generated.  Once you've set all your options, click Go.  You will see the generated JavaScript in the preview pane, and if you chose to save the file, a file with the .js extension will be created on disk.  The JavaScript generated from my data contract classes looks like this: 
 
if (typeof BB === "undefined") {BB = {};}

if (typeof BB.contracts === "undefined") {BB.contracts = {};}
 
BB.contracts.Address = function () {
    /// <summary>***WARNING*** For IntellSense only.  You should never create an instance of this object from code. ***WARNING***</summary>
    /// <field name="line1" type="String">The first line of the individual's address.</field>
    /// <field name="line2" type="String">The second line of the individual's address.</field>
    /// <field name="city" type="String">The city where the individual resides.</field>
    /// <field name="state" type="String">The state where the individual resides.</field>
    /// <field name="zipCode" type="String">The ZIP code where the individual resides.</field>
};

BB.contracts.Individual =
function
() {
    /// <summary>***WARNING*** For IntellSense only.  You should never create an instance of this object from code. ***WARNING***</summary>
    /// <field name="id" type="Object">The ID of the individual's record.</field>
    /// <field name="firstName" type="String" mayBeNull="true">The individual's first name.</field>
    /// <field name="lastName" type="String" mayBeNull="true">The individual's last name.</field>
    /// <field name="gender" type="Number">The individual's gender. Possible values: 0 (Female), 1 (Male), 2 (Unknown).</field>
    /// <field name="mailingAddress" type="BB.contracts.Address" mayBeNull="true">The address where the individual should receive all postal mail correspondence.</field>
    /// <field name="phoneNumbers" type="Array" elementType="BB.contracts.PhoneNumber">A list of the individual's phone numbers.</field>
};

BB.contracts.PhoneNumber =
function
() {
    /// <summary>***WARNING*** For IntellSense only.  You should never create an instance of this object from code. ***WARNING***</summary>
    /// <field name="number" type="String">The formatted phone number.</field>
};
 
Note that there are no fields or methods on these objects; this is because Visual Studio only needs the comments to provide IntelliSense.  Also note the data types in some of the field comments.  Many are intrinsic JavaScript data types like String and Number, but others actually point to other types created by the utility.  The utility can detect when a data member points to another type within the same assembly and will reference that type appropriately in the XML comments.  Also note the gender field on the Individual object.  The Gender data member in our data contract is an enum type, so the field's description has been built to indicate the epxected values for this field.
 
Reference the Generated File
 
In my example web application, I have two JavaScript files: service.js and myapp.js.  The first file, service.js, is the file I've written for my library and contains methods for accessing my WCF web service.  The second file, myapp.js, is where my application-specific logic resides.  Here's what service.js looks like:
 
if (typeof BB === "undefined") {BB = {};}

BB.Service =
function () {
   
/// <summary>Provides interaction with the client and the web service.</summary>
};

BB.Service.prototype.getIndividual =
function (id) {
   
/// <summary>Returns an individual object for the given ID.</summary>
    /// <param name="id" type="Number" integer="true">The ID of the individual's record.</param>

    // Send a synchronous request to the web server.   
   
var req = new XMLHttpRequest();
    req.open(
"GET", "http://www.mysite.com/myservice.svc/individuals/" + id.toString() + "/result.json", false);
    req.setRequestHeader(
"Content-type", "application/json");
    req.send();
   
   
// Parse the response text using the JSON utility and return it.
   
return JSON.parse(req.responseText);
};

Note that the file contains a type called Service with one function on its prototype called getIndividual().  The getIndividual() function takes an ID and returns an Individual object from the server.  I've already added XML comments to indicate everything but the return type, which up until now I couldn't do.  Now that I've generated a JavaScript file from my data contracts, however, I can now specify a return type from that generated file:
 
/// <reference path="contracts.js" />

if (typeof BB === "undefined") {BB = {};}

BB.Service =
function () {
   
/// <summary>Provides interaction with the client and the web service.</summary>
};

BB.Service.prototype.getIndividual =
function (id) {
   
/// <summary>Returns an individual object for the given ID.</summary>
    /// <param name="id" type="Number" integer="true">The ID of the individual's record.</param>
    /// <returns type="BB.contracts.Individual">The Individual object.</returns>

    // Send a synchronous request to the web server.   
   
var req = new XMLHttpRequest();
    req.open(
"GET", "http://www.mysite.com/myservice.svc/individuals/" + id.toString() + "/result.json", false);
    req.setRequestHeader(
"Content-type", "application/json");
    req.send();
   
   
// Parse the response text using the JSON utility and return it.
   
return JSON.parse(req.responseText);
};
 
 
Here I've added a "returns" XML comment to the getIndividual() function.  I've also added a "reference" comment to the top of the file; this is how Visual Studio knows to look for BB.contracts.Individual in my contracts.js file.
 
Now in myapp.js I have some JavaScript to call the getIndividual method in service.js.  Here's what that code looks like:
 
/// <reference path="service.js" />

var showMailingAddress = function () {
   
   
// Create the service.
   
var svc = new BB.Service();
   
   
// Get the individual's record.
   
var ind = svc.getIndividual(96);
};
 
In this file, I only need to add a reference XML comment to point to service.js; since service.js references contracts.js, Visual Studio will pick up contracts.js as well and show IntelliSense for that file.  In the showMailingAddress() function, the variable "ind" represents an instance of the BB.contracts.Individual type, and since the getIndividual() function indicates this as its return type, I now get IntelliSense on my "ind" variable:
 
 
Since the "mailingAddress" property in contracts.js points to BB.contracts.Address as its type, I also get IntelliSense on that field's properties:
 
 
Here are a couple of tips that have helped me work with JavaScript IntelliSense:
 
  • Turn on the status bar in Visual Studio.  When JavaScript IntelliSense is updated for a file, the status bar shows the status of the update and will notify you if there was a problem generating the IntelliSense.  To turn on the status bar, go to Tools > Options, and under the Environment > General section, check on the "Show status bar" option.  This will show the status bar at the bottom of the Visual Studio window.
  • Visual Studio updates JavaScript IntelliSense when Visual Studio is idle.  If you need to force Visual Studio to update the IntelliSense immediately, for instance after you've updated the XML comments in your file, press Ctrl-Alt-J or select the "Update JScript IntelliSense" menu item from the Edit > IntelliSense menu.
  • Visual Studio only provides IntelliSense from XML comments when the function or field is referenced from another file, meaning if you mark up a function or field in a JavaScript file, you will not see IntelliSense from those XML comments elsewhere in the same document.  I've been told that Visual Studio 2010 will address this shortcoming, but for now I've gotten around it by factoring my code into separate JavaScript files and combining them when I build my project (which is a good practice anyway).
 
There's a lot to learn about JavaScript IntelliSense in Visual Studio, so be sure to read the links mentioned at the beginning of this article.  The utility, its source code, and the example data contracts and JavaScript files are available for download in the Related Downloads section at the bottom of this page.
 
 
 
iBBDemo - Blackbaud iPhone Browser Simulator
Wednesday, February 18, 2009
 
** Updated 11/25/2009 - More updates to work with latest Safari 4.04 (531.21.10) **

** Updated 8/25/2009 - More updates to improve Safari 4.x compatibility **
 
 
Watch screen cast

Lately we have been doing a lot of work with rendering Web content optimized for mobile devices.  One of the most popular mobile devices is Apple's iPhone.  Many times I will be giving a presentation on a Windows machine and have no way to demonstrate how our content would look on mobile Safari, the iPhone Web browser.  I have often times longed to be able to test against my localhost Web server as well.
 
Enter Webkit (Safari for Windows)
 
So one day it dawned on me that Webkit (Safari's rendering engine) is VERY similar on Safari for Windows and the iPhone.  Could I somehow embed just the rendering component into a native Windows application and give it enough polish to do a decent job of simulating the iPhone Web browsing experience?  After a weekend of hacking the answer is YES.  iBBDemo correctly renders Webkit targeted html including the custom -webkit CSS extenstions, effectively giving us a compelling demo/test platform for iPhone Web content from the comfort of a Windows desktop (Note, I have only tested on Vista).
 


























Figure 1: Render iPhone Web Browser Content on Windows with the correct user agent!



Free for the Community!
 
Since I think this could be broadly useful and fairly unique I am releasing it here on labs as an unsupported utility.  I also put together a short 7 minute screen cast overview of iBBDemo.  Watch screen cast 


Okay how do I get started?
 
1) Download Safari for Windows  (The latest version as of this writing is 4.x)
 
If you are running Safari 3.x:
 
If you are running Safari 4.x
** NOTE: For the 4.x version, make sure you make a folder for iBBDemo and copy it in there.  The reason is, with 4.x iBBDemo will grab the DLL dependencies from Safari, and copy them local.  It will then use registration-free COM to invoke WebKit.DLL as a COM object.  This is required because Safari 4.x does not fully expose WebKit to COM, and I don't want to muck with the user's registry.  BTW, simply registering WebKit is not enough.
 
 
3) Extract and execute iBBDemo.exe (Safari 3.x) or iBBDemo4.exe (Safari 4.x)
 
Have fun!
 
Shaun Sullivan
CTO, Blackbaud, Inc.
shaun dot sullivan at blackbaud dot com
 
 
Kintera Connect, BBNC, RE and Infinity "Eleven" - Better together.
Tuesday, August 19, 2008
We have been hard at work as we integrate the Kintera and Blackbaud technology and teams.  The incredibly robust APIs offered by all of these systems is paving the way to a unification of BBNC, Blackbaud Enterprise CRM and Kintera Sphere on a common technology platform.  Internally we are calling it Infinity "Eleven" (sorry Spinal Tap!). 
 
That's cool, but with the power of these APIs you can do a LOT today, and we are not forgetting RE7.  Join me (Shaun Sullivan, CTO) in an 18 minute screen cast as I walk through some exciting developer-centric demonstrations exercising Kintera Connect, RE:API and Infinity together.  (Warning, it's also an "11" on the geek-o-meter...)
 
In addition, I'll provide some early detail on our plans to offer excellent Sphere and RE7 integration "in the box."  There are literally hundreds of customers out there with both solutions and we are committed to delighting you all.
 
Next time, I'll reveal some cool demos and details around Blackbaud NetCommunity and Infinity, so stay tuned if you are a BBNC guru...
 
A Tour of Infinity's Dynamic Help Engine
Tuesday, August 05, 2008
Usability is a key tenet of the Infinity platform.  A critical aspect of usability is a modern help system.  Infinity's radical extensibility model presented some interesting challenges to the documentation team.  How would we present help that is perfectly in context, respecting a user's security rights and a dynamic user experience?
 
In addition, our goal was to offer a help system that seamlessly integrated customer-specific help content along with the built in documentation, presented in a unified, searchable fashion. 
 
The Blackbaud documentation team worked in concert with the engineering team to build a world-class, dynamic, user-extensible help engine.  Denise Kadilak, a technical writer on the documentation team, has posted a short screen cast covering some of the key highlights of this award winning system.
 
 
 
 
Introducing the Infinity Excel Ribbon Add-in
Monday, July 28, 2008
One of the goals of the Infinity platform has always been to make clients' data easily and securely accessible from various endpoints other than the traditional shell (we call this "reach").  To date, we've delivered several "outside the shell" experiences with Yahoo! Widgets, Vista Gadgets, and the KPI Web Dashboard.  The latest example we've developed is an Excel ribbon add-in that will allow users to add Infinity ad-hoc query, data list, and KPI data to an Excel spreadsheet.  The data added to the spreadsheet is live, meaning that it can be refreshed on-demand or each time the spreadsheet is opened.  Best of all, the spreadsheet can be sent to other users who do not have the add-in installed while retaining the live data and much of its interactive features.

Here’s a quick overview of how the add-in works.

To install the add-in, a user will download a small setup.exe file from the web server where their Infinity-based application is installed.  This executable bootstraps most of the prerequisites (the .NET Framework, etc.) for the add-in as well as the add-in itself.  After the add-in is initially installed, it will have the ability to update itself via Microsoft’s ClickOnce technology, so the user never has to worry about checking for updates manually.

Once the add-in is installed, the user should see a new Blackbaud tab on his ribbon the next time he opens Excel:
 
 
The user has three options for adding his Infinity data to his spreadsheet: ad-hoc query, data list, and KPI.  Each of these three options has a similar workflow.  The user clicks the button representing the type of data he wishes to add to the spreadsheet (I’ll use data list as an example) and is presented with a dialog where he can select a database and the appropriate data:
 
 
Here I’ve searched for and chosen the Constituent 5 Year Giving List.  Because this data list requires a context record for its data, I will be presented with a search form when I click OK so I can locate the context record:
 
 
Once I’ve selected a context record, my data list data will be added to my spreadsheet:
 
Notice the blue region on the left.  That region represents the various parameters available for this data list.  From here I can narrow down my results with the same types of options available to me in the Infinity shell, such as drop-down lists for parameters whose values are represented by value lists, simple data lists or code tables:
 
 
Once I fill in or select a value for any of the parameter fields, my data automatically refreshes.
 
Also note the Context Record parameter at the bottom of the list.  If I select the cell containing the context record name, the “Choose Context Record” button in the ribbon will become enabled:
 
 
Clicking this button will allow me to select a different context record using the same search form in the earlier example.  Once I’ve chosen the new context record, the data will again automatically refresh:
 
 
Of course the user can extend the presentation of data with the full suite of features of Excel, such as formatting, charts, etc.  For instance, if I want a chart that shows my constituent’s gifts, pledges and payments broken down by fiscal year using the data from this data list, I can simply highlight the appropriate range and insert a chart using the Insert tab on the Excel ribbon:
 
 
We're very excited about this new feature, because by leveraging Excel's rich set of functionality, we're giving our users endless ways to view their data without the complexity of other solutions such as writing custom reports.
A Peek at Infinity Pervasive Search
Saturday, April 12, 2008

Infinity-powered applications will soon get an integrated, pervasive search experience. In this really short (7 minute) screen cast we'll do a high level overview and some quick demos. Kudos to Ben Rice and Paul Gibson, the architects behind this stuff. All I contributed was crazy ideas :) We're super excited about the potentially far reaching implications of this platform feature.

Watch or download the pervasive search screencast
Infinity APIs in the Cloud
Tuesday, April 08, 2008
The Infinity platform has been shipping with Blackbaud Enterprise CRM and Blackbaud Direct Marketing for almost a year now. This year will bring us the Infinity+NetCommunity powered offering Scorpio (code name). In the simplest terms Scorpio can be described as a "standalone" version of Blackbaud NetCommunity, meaning it can bring all the Web communication power of NetCommunity to folks that don't currently have an investment in The Raiser's Edge or Blackbaud Enterprise CRM.
 
Since its Web-centric CRM functionality is built on Infinity, Scorpio will also serve as a great strategic starting point for an organization planning to ultimately deploy a total Blackbaud solution centered around the Infinity platform.

Of course Infinity is the technology platform that will power all future generations of our current products (The Researcher's Edge, Raiser's Edge, Financial Edge, and all the other Edges...).

So with all that coming, and given that with Infinity we have a rich, standards-based Web API, people are asking the question: "What does this mean to me when I migrate from the 7.x generation of Blackbaud products to their shiny new 8.0 versions?"
While we don't have all the answers yet, in this short screencast we'll do a high level overview of our current thinking on this topic, and even give you an early peek at an exciting new research area focused on fostering developer ecosystems around our future offerings - The Cloud Catalog.
 
 
Infinity Puts the I in iPhone
Tuesday, April 01, 2008

One of the key tenets of our Infinity Web platform is improving "reach." We want to reach the maximum number of users, and wherever possible, let them consume information via their medium of their choice. We have already nailed a few scenarios (RSS, Web Dashboards, Web Services API).

The next logical area to focus on when improving reach is support for mobile devices and deep support for cross-platform via A-grade browsers. When we're ready to take the wraps of code name "Mobius," I'll do a screencast on this. For now I have a nice example fresh from the labs. Check out this cool proof of concept that brings some basic CRM-integrated search, map, and calling capabilities to a nice little Web UI designed for iPhone. You can still run it in any browser, but it just doesn't sizzle like it does on my sassy little iPhone :) What's really cool is it uses standard API code, no magic.

Kudos to Ben Jacobs and John Lunsford, two of the many super devs on the Blackbaud Enterprise CRM team. They pulled this together and had me hounding for more, while still having a "day job." Of course we'll go a lot broader than iPhone, but for now, if you have one, try out our little app. It's pointing at the same database as the Infinity sandbox so play around in real time. Search for someone with a picture, it's cool. Hmmm, maybe Blackbaud will let me expense this thing...
 
Try iNfinity on your iPhone
(Enter username "BBLabs" and password "adminadmin_2" when prompted for credentials. Oh, and have fun finding the underscore key on your iPhone!)
 
Want to work for a company that loves building stuff with bleeding edge technology? Feel like doing your part in helping to change the world? If you have a passion for technology and you are interested in building applications that power the world's largest nonprofit organizations, you need to come work for us.

 
© 2008 Blackbaud, Inc.