Thursday, May 27, 2010

Reactive Extensions (Rx) for .NET: A few samples

Reactive Extensions is a framework published by Microsoft DevLabs. The framework's goal is to make event-driven programming easier, by providing observable push collections and tons of helper functions. I'll leave the rest of the plain text selling points to their own web site, though, and provide a few code examples instead.

Example: Calling several methods in parallel, and combining the results into an anonymous structure.

Imagine three possibly long-running methods, Foo, Bar and Baz:

int Foo()
{
Thread.Sleep(200);
return 42;
}

string Bar()
{
Thread.Sleep(500);
return "The answer is {0}! {1}";
}

string Baz()
{
return "Awesome!";
}

What you want to do be doing, is call all three of these independent methods, collect the results in a struct, and output it to the screen.

With plain .NET code, you'd whip up delegates, begininvokes and waithandles, such as:

var waitHandles = new List<WaitHandle>();
int fooRet = 0;
Func<int> foo = Foo;
var fooRes = foo.BeginInvoke(res => { fooRet = foo.EndInvoke(res); }, null);
waitHandles.Add(fooRes.AsyncWaitHandle);
string barRet = "";
Func<string> bar = Bar;
var barRes = bar.BeginInvoke(res => { barRet = bar.EndInvoke(res); }, null);
waitHandles.Add(barRes.AsyncWaitHandle);
string bazRet = "";
Func<string> baz = Baz;
var bazRes = baz.BeginInvoke(res => { bazRet = baz.EndInvoke(res); }, null);
waitHandles.Add(bazRes.AsyncWaitHandle);
WaitHandle.WaitAll(waitHandles.ToArray());
Console.Out.WriteLine(barRet, fooRet, bazRet);

Not a pretty sight, that's for certain, and it doesn't even begin to take into account anomalies in the results, or errors reported from any of the methods.

With Rx, the above becomes trivial. The Linq like syntax will, in essence, say that we want to join the results of three async executions, wait for them to
complete and print the results on success. If an error occurs, we'll show an exception.

Observable.Join(
Observable.ToAsync<int>(Foo)()
.And(Observable.ToAsync<string>(Bar)())
.And(Observable.ToAsync<string>(Baz)())
.Then((foo, bar, baz) =>
new { Foo = foo, Bar = bar, Baz = baz })
).Subscribe(
o => Console.WriteLine(o.Bar, o.Foo, o.Baz),
e => Console.WriteLine("Exception: {0}", e));

Opposed to the BeginInvoke mayhem further up, this is pretty good looking!

Should you wish to asynchronously execute the methods in order, that would be even more hairy without Rx, with several wait handle calls, possible helper methods, and who-knows-what. With Rx, it's actually even more trivial than the parallell execution.

(from foo in Observable.ToAsync<int>(Foo)()
from bar in Observable.ToAsync<string>(Bar)()
from baz in Observable.ToAsync<string>(Baz)()
select new { Foo = foo, Bar = bar, Baz = baz })
.Subscribe(o => Console.WriteLine(o.Bar, o.Foo, o.Baz));

Key here is the fact that it's *asynchronous*. The call to Subscribe will not block execution, so your application is free to do whatever it pleases while Foo, Bar and Baz execute.

Example: Event throttling.

Suppose you have an alert generating source, such as:

class EventFiringClass
{
public event EventHandler<EventArgs> Alert;

public void TriggerManyAlerts()
{
for (int i = 0; i < 200; ++i)
{
Thread.Sleep(100);
if (Alert != null)
{
Alert(this, null);
}
}
}
}

That could obviously generate a ton of alerts, with a mere 100 msec between each one. Adding a notification handler to this, such as

var ec = new EventFiringClass();
ec.Alert += (s, o) => Console.WriteLine("Alert Flood!");
ec.TriggerManyAlerts();

... would print the same message, each time the event was raised - and that's not necessarily something you'd want. Alerts, mouse events, keyboard events - anything that's usually repeated, but not necessarily wanted more than once - all can be easily throttled by Rx.

Adding a time throttled (they can also be e.g. count throttled) event handler to the above event would expand to:

Observable.FromEvent<EventArgs>
(h => ec.Alert += h,
h => ec.Alert -= h)
.Throttle(TimeSpan.FromMilliseconds(500))
.Subscribe(e => Console.WriteLine("Alert Throttled!"));

This won't output anything until the event stream has been silent for at least half a second.

While a fantastic feature for dealing with delayed button presses or mouse moves, the use case for alerts here is however intentionally shifty. With the above code, you wouldn't see a single alert if the stream of raised alert events was continous.

For alerts, and many other event sources, what we'd really want is to easily get distinct updates only - I'm interested in the first alert for error "Foo", not necessarily 500 more immediately following.

With Rx, implementing this involves a call to DistinctUntilChanged.

First of all, imagine our alert event now looks like:

public class AlertArgs : EventArgs
{
public string AlertCode { get; set; }
}
public event EventHandler<AlertArgs> Alert;

[...]
Alert(this, new AlertArgs {AlertCode = "Something exploded!"});

Only printing one distinct alert code at a time, then amounts to:

var ec = new EventFiringClass();
Observable.FromEvent<EventFiringClass.AlertArgs>
(h => ec.Alert += h,
h => ec.Alert -= h)
.DistinctUntilChanged(o => o.EventArgs.AlertCode)
.Subscribe(e => Console.WriteLine("Alert: {0}", e.EventArgs.AlertCode));
ec.TriggerManyAlerts();

Example: Asynchronously providing unique Tweets as an Observable collection, using Rx and Linq2Twitter.

The following sample app will use Linq2Twitter to check for new tweets at an interval of 30 seconds, and feed them through an observable Rx collection.

In my WPF test app, I've got it hooked to a list box named TweetList, as can be seen from the Subscribe handler. Also worth noting is the call to ObserveOn, which tells Rx to use the current WPF UI Dispatcher to call the subscription observer. By doing so, we won't have an issue with cross thread UI updates when showing the tweets, nor will we have to monkey around with Dispatcher.BeginInvoke to fix said issue.

private void InitTwitterListing()
{
var twitterCtx = new TwitterContext();
var seen = new Dictionary<string, bool>();
var tweetStream =
from t in Observable.Return(1)
.Concat(Observable.Interval(TimeSpan.FromSeconds(30)))
from tweet in GetUniqueTweets(twitterCtx, seen)
select tweet;
tweetStream.ObserveOn(new DispatcherScheduler(Dispatcher))
.Subscribe(tweet =>
TweetList.Items.Add(
String.Format("[{0}] {1}", tweet.CreatedAt, tweet.Text)));
}

private static IObservable<Status> GetUniqueTweets(TwitterContext ctx, Dictionary<string, bool> seenList)
{
var filter = new Func<Status, bool>(tweet =>
seenList.ContainsKey(tweet.StatusID) ? false : seenList[tweet.StatusID] = true);
return (from tweet in ctx.Status
where tweet.Type == StatusType.User &&
tweet.ScreenName == "einaros" &&
tweet.Count == 10 &&
filter(tweet)
select tweet).Reverse().ToObservable();
}

The most interesting part here is the tweetStream observable, which is initialized in the InitTwitterListing method. It will keep spewing values indefinitely, the first one after a timeout of TimeSpan.Zero seconds, then at an interval of 30 seconds. The actually selected values stem from the GetUniqueTweets method, which does a farily straight forward poll from Linq2Twitter.

For each new call to Linq2Twitter, 10 tweets will be requested. All returned tweets will then be filtered (and taken notice of, if not already seen), then reversed and returned as an Rx observable sequence.

Wednesday, May 26, 2010

Another SharePoint drag'n'drop framework sneak peek: Assigning task items

In this demo I'm pulling another one of my frameworks into the mix: SPDropBox. It makes for a general purpose hovering container, which can e.g. (as in the following demo) active site show users.

Combined with SPDrag, I can easily assign task list items to a user, simply by dragging it onto the user's entry in the SPDropBox view.

Check the demo:


Click the video above to watch it embedded (best in full screen), or Watch in new window


The code for this demo is nothing fancy, just a quick type-up to demonstrate how the current state of the SPDrag and SPDropBox libraries can be used.

In essence, I create a div container which lists users. Users are fetched from some server side code - in a prod solution, this should be lazy loaded and searchable. This user container is added to the dropbox, along with an icon.

In the latter part of the sample source, I use SPDrag to hook what I within SPDrag have defined as SPTask items, to the user entries of the user list. The drop handler gets a reference to the dropped task item, as well as the container it's dropped onto. List and item information are extracted, along with the id of the user from the drop targe. All of this then updates the list using the SharePoint 2010 client object model, and finally (asynchronously) refreshes the list.

var userContainer = $(document.createElement("div"));
var users = [<%= users %>];
for (var i = 0; i < users.length; ++i)
{
var user = users[i];
var userBox = $(document.createElement("div"));
userBox
.attr("grep:user", user.Id)
.addClass("usercontainer_user")
.html("<center><img width='50px' src='/_layouts/images/PERSON.GIF'/><br/>" + user.Name + "</center>");
userContainer.append(userBox);
}

grep.dropbox.addContainer("/_layouts/images/pplpkrgrp.png", "People", userContainer);

// Make SPDrag connectable
var l = grep.spdrag.lambda;
grep.spdrag.connect(userContainer.find(".usercontainer_user"),
[
l.item().is_of_type(grep.spdrag.Types.SPTask)
],
function (element, container)
{
var task = grep.spdrag.getData(element);
if (task)
{
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
list = web.get_lists().getById(task.ctx.listName);
listItem = list.getItemById(task.id);
listItem.set_item('AssignedTo', container.attr("grep:user"));
listItem.update();
clientContext.executeQueryAsync(
function () {
_SubmitFormPost(_CorrectUrlForRefreshPageSubmitForm(), false, true); },
function (e, x) { /* Error condition */ });
}
});

Related post: SPDrag: A soon released javascript framework to make the SP2010 UI drag'n'droppable

Tuesday, May 25, 2010

SPDrag: A soon released javascript framework to make the SP2010 UI drag'n'droppable

Last autumn I spent some time writing a javascript framework for SharePoint 2007, which made regular SharePoint UI elements drag'n'droppable. To make it flow with async postbacks, I had to pull a few dirty hacks into the standard SP javascript libs, and that made the framework too fragile to be released.

With SharePoint 2010, this is no longer the case. The standard libraries now have methods to do partial ajax-ish ui updates, as well as being much more suited for dynamic extensions. SPDrag is thus reborn, and I've begun writing new integrations.

The first SPDrag use is a plugin for my previously shown tree navigation control, which allows the user to move/copy files and folders by dragging them onto folders on the nav tree.

Check the demo:


Click the video above to watch it embedded (best in full screen), or Watch in new window


Other usage implementations of the SPDrag library will follow as I complete its transition to SP2010.

Regarding the navigation control itself, it will be open sourced in near future - pending a few license formalities. The same goes for the core SPDrag library, which is standalone from the navigation control, but provides the core connectability between e.g. files, folders, list & calendar items and e.g. the nav control, user lists, SP-hosted chat applications and so forth. In other words: if you're interested in any of this, either check back soon, or send me a tweet / email to show interest - and I'll keep you posted about downloads / project hostings.

Related post: Another SharePoint drag'n'drop framework sneak peak: Assigning task items

Friday, May 14, 2010

Very fast jQuery / WCF REST based SharePoint 2010 hierarchical nav control: Complete

The control, which I've blogged about in the past, features:
  • Complete hierarchical overview of an entire site collection, including document library folders.
  • Wiki and page libraries will, in addition to have their folders listed - as with document libraries - also list individual pages.
  • The entire site, list and folder tree can be navigated, regardless of which sub site or list you're currently browsing.
  • All data is cached on the client side, which means minimal traffic overhead, and very quick load time. The cache expire time can be customized.
  • Editable nodes all through the tree: you can reorder, change titles and hide nodes.
  • A quick link to hide or show the navigation control, and thus instantly grant more view space to the web parts on the page.
  • CSS based design, for easy styling.
At the bottom of the post you'll find a screencast, where I briefly explain the differences between this nav control, and the default treeview in SP2010. Note for those without sound: the first control shown is the default treeview - which won't show content of sites above the current site, nor sibling sites. About half-way into the screencast I enable the custom control.

Update: This solution has now been commercialized, and is available for purchase. Send me an email (link in the right pane) for further information.

Update 2 (January 2011): The newest version now has plugin support. The first released plugin, Cross Site Drag and Drop File / Folder Copying, is demonstrated here.

Older demonstration:



Click the video above to watch it embedded (best in full screen), or Watch in new window

Thursday, May 6, 2010

Using PostSharp AOP to simplify SharePoint 2010 Developer Dashboard timing

This is a 10 minute screencast where I demonstrate the basic functionality of the SharePoint 2010 Developer Dashboard, combined with the PostSharp AOP framework. By using AOP (Aspect Oriented Programming), you can extract the timing code into separate aspects and apply them to the methods of your choosing, rather than cluttering all the method bodies with specific timing code.

Watch the screencast:


I do apologize for the sound quality of the recording. This was my first time around with Microsoft Expression Encoder, and it seems that the longer I record, the more jittery the sound becomes. I tried stopping and restarting the recording every now and then to deal with the issue, but it's still somewhat choppy at times.

The powershell script I've built to enable / disable the developer dashboard:
enable-devdashboard.ps1

param([switch]$disable)

[reflection.assembly]::LoadWithPartialName("microsoft.sharepoint") >$null

if($disable -eq $false){
write-host -foreground green Enabling Developer Dashboard
stsadm -o setproperty -propertyname developer-dasboard -propertyvalue on >$null
$ws = [microsoft.sharepoint.administration.spwebservice]::ContentService
$ws.DeveloperDashboardSettings.DisplayLevel = [microsoft.sharepoint.administration.spdeveloperdashboardlevel]::On
$ws.DeveloperDashboardSettings.Update()
}
else {
write-host -foreground yellow Disabling Developer Dashboard
stsadm -o setproperty -propertyname developer-dasboard -propertyvalue off >$null
$ws = [microsoft.sharepoint.administration.spwebservice]::ContentService
$ws.DeveloperDashboardSettings.DisplayLevel = [microsoft.sharepoint.administration.spdeveloperdashboardlevel]::Off
$ws.DeveloperDashboardSettings.Update()
}

write-host Done

Here's the aspect code, which I put together at the end of the screencast. In this listing I've updated it to not emit any aspect code for non-debug builds.

[Serializable]
public class DeveloperDashboardTimedAttribute : OnMethodBoundaryAspect
{
#if DEBUG
public string Description { get; set; }

public override sealed void OnEntry(MethodExecutionArgs args)
{
string type = args.Method.DeclaringType != null ?
args.Method.DeclaringType.Name : "<no type>";
string scopeName = type +
"." + args.Method.Name +
(Description != null ? " [" + Description + "]" : "");
var sc = new SPMonitoredScope(scopeName);
args.MethodExecutionTag = sc;
}

public override sealed void OnExit(MethodExecutionArgs args)
{
var sc = args.MethodExecutionTag as SPMonitoredScope;
if (sc != null)
{
sc.Dispose();
}
}
#endif
}

Wednesday, May 5, 2010

Custom jQuery based quick launch treeview for SharePoint 2010

Update: There's an updated post on this control, available here.

Outdated post follows

I wrote about a control such as this some time ago, when I first started developing it for SharePoint 2007. Recently I've upgraded and rewritten large parts of it for SharePoint 2010, and it now utilizes custom REST WCF services and the updated APIs to do its job. SharePoint 2010 has a much improved default tree view, but I've wanted a few extra features - such as custom caching schemes and on-the-spot administration, which I haven't been able to do with the standard controls.

Take a look at the following screencast, where I explain a bit about what it is and does.

One feature I don't mention in the screencast, which is currently 80% upgraded to 2010, is the ability to drag pages from document libraries, onto the menu, for quick-linking pages. I think that's pretty cool as well.

Tuesday, May 4, 2010

Anonymously accessing list items through the SharePoint Client Object Model

Up until today I haven't found time to explore the obscure corners of the SharePoint 2010 Client Object Model. Keeping an eye on my Twitter client, I noticed Waldek Mastykarz mention trying to use it in an anonymous portal context - and hitting an error doing so. Problems such as these easily catch my interest (that's my favorite way of learning new stuff), so I set out to try the same myself.

I whipped up an empty SP2010 team site, created a dummy list and added an item to that. I then went on to create a simple SilverLight package, such as:

public partial class MainPage : UserControl
{
private ListItemCollection _items;

public MainPage()
{
InitializeComponent();
var context = new ClientContext("http://sp10dev");
_items = context.Web.Lists.GetByTitle("TestList").GetItems(new CamlQuery { ViewXml = "100" });
context.Load(_items, items => items.Include(item => item["Title"]));
context.ExecuteQueryAsync(
(sender, args) => Dispatcher.BeginInvoke(ShowStuff),
(sender, args) => Dispatcher.BeginInvoke(() => MessageBox.Show("Request failed. " + args.Message + "\n" + args.StackTrace)));
}

private void ShowStuff()
{
foreach (var item in _items)
{
Output.Text += item["Title"] + "\n";
}
}
}

After adding this to the portal as a "Silverlight Web Part", using the default template, and enabling anonymous access to the portal, I got the following error:
Request failed. The method "GetItems" of the type "List" with id "{...}" is blocked by the administrator on the server.


This was quite unexpected, as I was able to retrieve information about the Web object, as well as enumerate lists (even a few hidden ones) in the portal.

Digging a bit further, I combined an exception I noticed in Fiddler (Microsoft.SharePoint.Client.ApiBlockedException), with the class information found in the client.svc endpoint. In Reflector, this brought me through the SharePoint 2010 client service code, to a class called SPClientServiceHost, which has a method named IsMethodBlocked. Following this trail even further, it turns out that there's a SPClientCallableSettings class, exposed as ClientCallableSettings on the SPWebApplication object - and that's the key. Turning to PowerShell for a second, I enumerated what turns out to be the default settings for the AnonymousRestrictedTypes property:


So apparently anonymous users, using the Client Object Model, are blocked from using
  • GetItems and GetChanges on SPLists
  • GetChanges and GetSubwebsForCurrentUser on SPWebs
  • GetChanges on SPSites

The good news, however, is that the ClientCallableSettings value can be adjusted to allow anonymous user access to one or more of these methods.

Doing this with PowerShell:

$webapp = Get-SPWebApplication "http://sp10dev"
$webapp.ClientCallableSettings.AnonymousRestrictedTypes.Remove([microsoft.sharepoint.splist], "GetItems")
$webapp.Update()

Be sure to replace "http://sp10dev" with whatever url your target webapp has. After doing this, anonymous calls to GetItems will work for that web application. The changes are persisted in the SharePoint database, and last until you change the setting again, or recreate the web application.

Update: I can't say for certain why GetItems() has been blocked by default, but this much I can say:
  • Per-item security is still upheld, with GetItems enabled. If anon doesn't have access to a list item, it won't be returned.
  • Even with GetItems disabled, the client side object model can be used by anonymous users to *add* items, granted that the list permits anon additions.