Refactoring with LINQ & Iterators: FindDescendantControl and GetDescendantControls

A while back I put together a quick and dirty implementation of a FindControl extension method:

public static T FindControl<T>(this Control root, string id) where T : Control
{
    Control c = root;
    Queue<Control> q = new Queue<Control>();

    if (c == null || c.ID == id)
        return c as T;
    do
    {
        foreach (Control child in c.Controls)
        {
            if (child.ID == id)
                return child as T;
            if (child.HasControls())
                q.Enqueue(child);
        }
        c = q.Dequeue();
    } while (c != null);
    return null;
}

It got the job done (if the control exists!), but I think we can do better.

Refactoring with Iterators

My first concern is that the method is doing too much. Rather than searching for the provided ID, the majority of the code is devoted to navigating the control’s descendents. Let’s factor out that logic into its own method:

public static IEnumerable<Control> GetDescendantControls(this Control root)
{
    var q = new Queue<Control>();

    var current = root;
    while (true)
    {
        if (current != null && current.HasControls())
            foreach (Control child in current.Controls)
                q.Enqueue(child);

        if (q.Count == 0)
            yield break;

        current = q.Dequeue();
        yield return current;
    }
}

The new method is almost as long as the old one, but now satisfies the Single Responsibility Principle. I also added a check to prevent calling Dequeue() on an empty queue. For those that have studied algorithms, note that this is a breadth-first tree traversal.

Now we can update FindControl:

public static T FindControl<T>(this Control root, string id) where T : Control
{
    Control c = root;

    if (c == null || c.ID == id)
        return c as T;

    foreach (Control child in c.GetDescendantControls())
    {
        if (child.ID == id)
            return child as T;
    }
    return null;
}

With the control tree traversal logic extracted, this updated version is already starting to smell better. But we’re not done yet.

DRY? Don’t Repeat Someone Else, Either

My second concern is how we’re checking for the ID in question. It’s not that the equality operator is a bad choice, as it will work in many scenarios, but rather that it’s not consistent with the existing FindControl method. In particular, the existing FindControl understands naming containers (IDs that contain ‘$’ or ‘:’). Rather than implement our own comparison logic, we should just leverage the framework’s existing implementation:

public static T FindControl<T>(this Control root, string id) where T : Control
{
    if (id == null)
        throw new ArgumentNullException("id");

    if (root == null)
        return null;

    Control c = root.FindControl(id);
    if (c != null)
        return c as T;

    foreach (Control child in c.GetDescendantControls())
    {
        c = child.FindControl(id);
        if (c != null)
            return child as T;
    }
    return null;
}

Fun fact: FindControl will throw a NullReferenceException if id is null.

Refactoring with LINQ

So we have extracted the descendant logic and leaned on the framework for finding the controls, but I’m still not quite satisfied. The method just feels too…procedural. Let’s break down what we’re really trying to do:

  1. Look at the current control and all its descendants.
  2. Use FindControl on each with the specified ID.
  3. When we find the control, return it as type T.

As the subheading might suggest, we can express these steps quite nicely with LINQ:

  1. var controls = root.AsSingleton().Concat(root.GetDescendantControls());
  2. var foundControls = from c in controls
                        let found = c.FindControl(id)
                        where found != null
                        select found;
  3. return foundControls.FirstOrDefault() as T;

Behind the scenes, this is how I might have thought through this code:

  1. We use AsSingleton() (my new preferred name, to align with F#’s Seq.singleton, for AsEnumerable(), which I introduced here) and Concat() to prepend root to the list of its descendants, returned as a lazy enumeration.
  2. We use a query over those controls to retrieve matches from FindControl(), again returned as a lazy enumeration.
  3. We grab the first control found, or null if none match, and return it as T.

Because all our enumerations are lazy, we put off traversal of the entire control tree until we know we need to. In fact, if our ID is found in the root control, GetDescendantControls() won’t even be called! Through just a bit of refactoring, we have both an efficient and readable solution.

For completeness, here’s the final version with a more descriptive name to contrast with the existing FindControl():

public static T FindDescendantControl<T>(this Control root, string id) where T : Control
{
    if (id == null)
        throw new ArgumentNullException("id");

    if (root == null)
        return null;

    var controls = root.AsSingleton().Concat(root.GetDescendantControls());

    var foundControls = from c in controls
                        let found = c.FindControl(id)
                        where found != null
                        select found;

    return foundControls.FirstOrDefault() as T;
}

I have added these methods, along with AsSingleton() and a host of others, to the SharePoint Extensions Lib project. Check it out!

So what’s the symbology there?

[This is the first in a series of posts I will be writing as part of a graduate course on Emerging Practices in Human-Computer Interaction, cross-posted from our class blog. I’ll do my best to make the posts stand on their own outside of course content, but feel free to ask for clarification if I fail to do so.]

As I read the opening chapter of Paul Dourish‘s Where the Action Is, I couldn’t help but pause to reflect on the phases through which interaction has evolved over the years: electrical, symbolic, textual and graphical. Dourish characterizes the transition between phases as “a general trend that emerges in a number of different ways”(7). What he didn’t mention is that each new interaction paradigm has served to supplement the former in a continual coevolution. This coevolution will be essential as we try to make the most of the new devices and manifestations of computational power, particularly with relation to multi-core and distributed processing.

As a mathematician and language geek, I’m most drawn to interaction optimizations at the symbolic level. Through my programming career, I’ve been exposed to dozens of symbolic abstractions, ranging from Logo and my TI-85 to academic amusement with Scheme to “real-world” languages like C and Java. For the most part, however, the languages have been more similar than different. And with the exception of a course on functional languages, the style of programming was always the same: tell the computer how to push these bits around. For the majority of problems, that was simple enough, particularly with the steady march of CPU speeds in step with Moore’s Law.

Well physics decided to step in the way of our 20-GHz CPUs, leaving us instead with dual- and quad-core systems. There’s still an increase in processing power, but taking advantage of it requires new ways of thinking. Among these are various new (or new-again) symbolic abstractions that will be essentially to get developers back to the point where the electrical systems are sufficiently hidden that we can get on with the real work of building the next generation of textual and graphical interfaces. As a developer on the Microsoft platform, there are two in particular that are of interest: Axum and F#.

Axum

According to Microsoft, “Axum is a language that builds upon the architecture of the Web and principles of isolation, actors, and message-passing to increase application safety, responsiveness, scalability, and developer productivity.” In other words, it’s a domain-specific language (DSL) built specifically for scenarios involving distributed and concurrent computation. I haven’t built anything with it yet, and at this point it remains very much experimental, but the concept has a lot of promise to faciliate the creation of applications and frameworks that can seamlessly handle the new architectures that have emerged. For more information, check out the Axum page on MSDN.

F#

Functional languages have been around for a very long time, and they are based on the lambda calculus which has been around even longer. But only recently have they started to come back into mainstream view, due in part to new functional languages for the major development platforms: Clojure and Scala for the Java Virtual Machine, and F# for .NET. The other reason for this comback is the ease with which functional languages handle the problem of concurrency through the use of immutable values and data structures. These languages also provide other higher-level abstractions that move developers away from specifying “how to push these bits around” and more toward specifying what they are trying to accomplish.

In both cases, there is clear value in solving the difficult problems once and letting symbolic abstractions shield the rest of us from ever having to think about it at a low level. It will always be necessary to have some knowledge of what’s happening behind the scenes, just as managed memory doesn’t free the developer from memory considerations completely. But leaning on advanced symbolic abstractions is one more way to advance the state-of-the-art in HCI.

Posted in General. Tags: . Comments Off on So what’s the symbology there?

SPExLib Release: These Are A Few Of My Favorite Things

It’s no secret that I’m a big fan of using extension methods to simplify work with the SharePoint object model. Wictor Wilén has allowed me to incorporate many of my “greatest hits” (and some new techniques! more on those in coming weeks) into his excellent SharePoint Extensions Lib project, which added a new release over the weekend (also see Wictor’s announcement).

It’s also worth pointing out that this isn’t just a library of extension methods. It also includes some useful base controls and auxilary classes, including SPDisposeCheckIgnoreAttribute and SPDisposeCheckID with IntelliSense support. If you have classes or methods that you simply can’t live without, we’d love to incorporate them as well.

Additional reading on some of the extensions included:

SPExLib Features

  • Namespace: SPExLib.General
    • Extensions to the .NET 3.5 SP1 Fx
  • Namespace: SPExLib.SharePoint
    • Extensions to the SharePoint object model.
  • Namespace: SPExLib.SharePoint.Linq
    • Linq extensions for the SharePoint object model. Including Linq operations on SPWeb/SPSiteCollection using dispose-safe-methods.
  • Namespace: SPExLib.SharePoint.Linq.Base
    • Implementation of IEnumerable<T> on the SPBaseCollection, which Linq-enables all collections in the SharePoint object model.
  • Namespace: SPExLib.SharePoint.Security
    • Extension methods that simplifies impersonation tasks on SPSite and SPWeb objects
  • Namespace: SPExLib.SharePoint.Tools
    • SPDispose checker utilities
  • Namespace: SPExLib.Diagnostics
    • Debug and Trace features
  • Namespace: SPExLib.Controls
    • Template classes for WebParts and EditorParts

Check it out!

Workflow at Iowa SharePoint User Group

I will be presenting at the next Iowa SharePoint User Group meeting on Wednesday, June 3:

Business Process / Workflow / Forms

This month is a two-part session, focusing on business processes, workflows, and forms in SharePoint.  The meeting will cover:

  • Workflow basics
  • Out of the box workflow templates
  • Configuring / customizing workflows
  • Options for building workflows
  • Building workflows with SharePoint Designer

Immediately following the User Group, please join us for a Lunch and Learn with Valeri Topel of KnowledgeLake. Continuing on the same theme, Valeri will have a presentation and demos showcasing how you can leverage SharePoint for content management business solutions.  Realize a faster ROI and a lower cost of ownership using the platform-based Enterprise Content Management in SharePoint with the KnowledgeLake Document Imaging and Capture system.  Easily manage millions of paper documents, emails, reports and more. Streamline document processing and increase your workers’ efficiency.

Lunch will be provided.

Details:

  • When: Wednesday, June 3, 2009
    Registration: 8:30–9:00 AM
    Event: 9:00–11:00 AM
    Networking/Q&A: 11:00–11:30 AM
    Lunch & Learn: 11:30 AM–1:00 PM
  • Where: DMACC Ankeny Campus, 2006 South Ankeny Blvd, Ankeny, Iowa 50023 (map)
    Building 24, Health Sciences Building (map); Room 216 (map)
  • RSVP: https://www.clicktoattend.com/invitation.aspx?code=138602

If you have ideas or requests for future IASPUG topics, or if you have a topic you would like to present, please send them to info@sharepointia.com.

Posted in Community. Tags: . Comments Off on Workflow at Iowa SharePoint User Group

SPWebConfigModification Works Fine

Manpreet Alag‘s recent post, SPWebConfigModification does not work on Farms with multiple WFEs, has been making its rounds on Twitter and the link blogs. A post title like that is sure to get attention, but is it really true? After looking a bit closer, I don’t believe it is.

The post suggests that this doesn’t work:

SPSite siteCollection = new SPSite("http://MOSSServer/");
SPWebApplication webApp = siteCollection.WebApplication;
// ...
webApp.WebConfigModifications.Add(modification);
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

But this does:

SPWebService.ContentService.WebConfigModifications.Add(modification);
SPWebService.ContentService.Update();
SPWebService.ContentService.ApplyWebConfigModifications();

Drawing this final conclusion:

Instead of adding modifications to WebConfigModifcations of SPWebApplication object, we are using SPWebService.ContentService to call ADD and UPDATE methods. Whenever required, it is always advised to use SPWebService.ContentService to make the modifications rather than accessing Farm instance through SPWebApplication.

The suggestion is that there’s a problem with applying the changes through webApp.Farm. But that Farm is just SPFarm.Local:

public SPSite(string requestUrl) : this(SPFarm.Local, new Uri(requestUrl), false, SPSecurity.UserToken)
{
}

So the last line is essentially equivalent to this:

SPFarm.Local.Services.GetValue<SPWebService>()

Taking a peek at ContentService, we find this definition:

public static SPWebService get_ContentService
{
    if (SPFarm.Local != null)
    {
        return SPFarm.Local.Services.GetValue<SPWebService>();
    }
    return null;
}

The modified sample isn’t actually doing anything different to apply the changes! So the problem is either in how SharePoint handles Web Application-scoped web config changes, or that the changes aren’t being applied correctly. The latter is much more likely than the former, and indeed the solution is actually quite simple: just look for the only other significant difference between the code samples.

webApp.WebConfigModifications.Add(modification);
webApp.Update(); // Oops!
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

A quick PowerShell session or console app would have verified that the config changes weren’t being saved to the database.

So what have we learned?

  1. Always call Update() after making changes to an SPPersistedObject (like SPWebApplication or SPWebService).
  2. SPWebService.ContentService is a shortcut for SPFarm.Local.Services.GetValue<SPWebService>.
  3. Check your code carefully before blaming the SharePoint API!

TextReader.TryReadLine And Idiomatic Code

Today I reread a post by Eric Lippert on High Maintenance code. It’s an interesting read in general, but some of the comments got me thinking about idioms in code. The discussion started with this bit of C#:

string line;
while ((line = reader.ReadLine()) != null)
    yield return line;

A familiar pattern in C and C++, but it just doesn’t feel right for C#. Eric cites this is a flaw “because it tries to do so much in one line.” His rewrite uses the following instead:

while (true)
{
    string line = reader.ReadLine();
    if (line == null)
        yield break;
    yield return line;
}

While certainly easier to read, it still seems like a lot of work. Commenter Sebastien Lorion suggests  this is a flaw in the API: “…we would not need such a hack or the awkward code you posted if the method was better designed.” I’m not sure I agree—ReadLine implies the line read will be returned, and if there’s nothing to read then nothing (null) should be returned. Sebastien’s “better design” doesn’t make sense idiomatically; what he really wants is TryReadLine, which would closely match his suggested signature of bool ReadLine(out string line). This strikes me as a perfect extension candidate:

public static bool TryReadLine(this TextReader reader, out string line)
{
    line = reader.ReadLine();
    return line != null;
}

With which we can write a more C#-idiomatic yet compact version of the original code:

public static IEnumerable<string> GetLines(this TextReader reader)
{
    string line;
    while (reader.TryReadLine(out line))
        yield return line;
}

Now one could argue whether or not TryReadLine() should catch the possible exceptions from ReadLine(), but that’s not the point. The point is that C# has an established pattern for methods that return a boolean indicating success in populating an out parameter, and code written as such is easier to read in a C# context.

It’s also interesting to note how the coding patterns can evolve with language features. For example, F# happens to have an Option type that aligns perfectly with this pattern: it either has Some value or is None. Paired with pattern matching, this presents a superior alternative to booleans and out parameters. So in idiomatic F# we would write TryReadLine like this instead:

namespace System.IO
    [<AutoOpen>]
    module TextReaderExtensions
        type System.IO.TextReader with
            member r.TryReadLine() =
                match r.ReadLine() with
                | null  -> None
                | line  -> Some line

Which could be used tail-recursively to fetch a sequences of lines:

            member r.Lines =
                let rec lines_core (tr : TextReader) =
                    seq {
                        match tr.TryReadLine() with
                        | None   -> yield! Seq.empty
                        | Some l -> yield l; yield! lines_core tr
                    }
                lines_core r

Eric ends his article with excellent advice: “Whenever you write a method think about the contract of that method.” As a corollary to that, whenever you write a method think about idioms that fit the method contract. An important part of maintainability is writing code that makes sense in the context of other code that has been written. Clever code that nobody can read isn’t particularly clever.

Posted in .NET, F#. Tags: . Comments Off on TextReader.TryReadLine And Idiomatic Code

Join SharePoint Lists with LINQ

I just read yet another post by Adam Buenz that got me thinking, this time about querying multiple SharePoint lists. Here’s the code he came up with:

var resultSet  = list1.Items.Cast<SPListItem>()
.Where(i => Equals (String.Compare(i["Property To Match #1"].ToString(), "Example String Literal"), 0))
.SelectMany(x => list2.Items.Cast<SPListItem>()
    .Where(i => Equals(String.Compare(new SPFieldLookupValue(x["Client"].ToString()).LookupValue, (string) i["Property To Match #2"]), 0)));

My first thought was that we could make it more readable with LINQ syntax:

var res = from SPListItem pi in list1.Items
          where pi["Property To Match #1"] as string == "Example String Literal"
          from SPListItem ci in list2.Items
          where new SPFieldLookupValue(ci["Client"] as string).LookupValue == pi["Property To Match #2"]
          select new { Parent = pi, Child = ci };

Behind the scenes, this will translate into equivalent extension method calls. The other adjustments are based on personal preference: ToString() can cause null reference exceptions, as string will not; and String.Compare() != String.Equals().

Next, let’s optimize the actual SharePoint queries. As a general rule we should always specify the desired ViewFields to eliminate unused data, and our first where clause should be handled with CAML if possible [see also, Is it a good idea to use lambda expressions for querying SharePoint data?].

var pItems = list1.GetItems(new SPQuery() {
    Query = "... ['Property To Match #1'] == 'Example String Literal'...",
    ViewFields = "..."
});
var cItems = list2.GetItems(new SPQuery() {
    ViewFields = "..."
});
var res = from SPListItem pi in pItems
          from SPListItem ci in cItems
          where new SPFieldLookupValue(ci["Client"] as string).LookupValue == pi["Property To Match #2"]
          select new { Parent = pi, Child = ci };

Now that we’re getting our data as efficiently as possible, we can look at what LINQ is doing with them. Behind the scenes, SelectMany is essentially implemented like this:

public static IEnumerable<TResult> SelectMany<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TResult>> selector)
{
    foreach(TSource element in source)
        foreach(TResult childElement in selector(element))
            yield return childElement;
}

For each item in our parent collection (source), the entire child collection is enumerated in search of items that match the predicate. This seems rather inefficient since we’re comparing the same values each time. Conveniently, LINQ provides a join operator for this purpose:

var res = from SPListItem pi in pItems
          join SPListItem ci in cItems
              on pi["Property To Match #2"]
              equals new SPFieldLookupValue(ci["Client"] as string).LookupValue
          select new { Parent = pi, Child = ci };

Behind the scenes, this translates into a call to the Join method:

var res = pItems.Cast<SPListItem>().Join(cItems.Cast<SPListItem>(),
              pi => pi["Property To Match #2"],
              ci => new SPFieldLookupValue(ci["Client"] as string).LookupValue,
              (pi, ci) => new { Parent = pi, Child = ci }
          );

Note that the left- and right-hand sides of the equals keyword are treated separately. The left-hand side operates on the first collection, the right-hand side operates on the second collection, and obviously both expressions must return the same type. This might be easier to see from an implementation of Join:

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
    this IEnumerable<TOuter> outer,
    IEnumerable<TInner> inner,
    Func<TOuter, TKey> outerKeySelector,
    Func<TInner, TKey> innerKeySelector,
    Func<TOuter, TInner, TResult> resultSelector)
{
    ILookup<TKey, TInner> lookup = inner.ToLookup(innerKeySelector);
    return from outerItem in outer
           from innerItem in lookup[outerKeySelector(outerItem)]
           select resultSelector(outerItem, innerItem);
}

So in our case, Join will build a lookup of all child items based on the lookup value, and then perform a SelectMany to cross join the parent items with the child items found from a lookup by the matched property. This dictionary lookup will almost certainly perform better than a full enumeration of the list, especially for larger lists and more complex keys.

Elegant Inline Debug Tracing

As much fun as it is to step through code with a debugger, I usually prefer to use System.Diagnostics.Debug and Trace with DebugView to see what’s happening in realtime. This is particularly handy to track intermediate results in higher-order functions that you might not be able to step into. However, it’s not always convenient to insert debugging statements amongst the composed expressions of F#, PowerShell or LINQ.

An alternative first came to mind while working in F#:

let dbg x = System.Diagnostics.Debug.WriteLine(x |> sprintf "%A"); x

(Read |> as “as next parameter to”.) We can then use this function anywhere to peek at a value, perhaps an intermediate list in this trivial example:

let data = [1..10]
           |> List.filter (fun i -> i%3 = 0) |> dbg
           |> List.map (fun i -> i*i)

Indeed [3; 6; 9] are traced as multiples of three. Not a particularly convincing example, but it should be pretty easy to imagine a more complex algorithm for which unintrusive tracing would be useful.

This works pretty well with F#’s |> operator to push values forward, but what about C#? Given my posting history, it shouldn’t be hard to guess where I’m going with this…

Extension Methods

So if |> is “as next parameter to”, the . of an extension method call might read “as first parameter to”. So we can implement a roughly equivalent function (sans F#’s nice deep-print formatter "%A") like so:

    public static T Debug<T>(this T value)
    {
        Debug.WriteLine(value);
        return value;
    }

    public static T Dbg<T>(this T value, string category)
    {
        Debug.WriteLine(value, category);
        return value;
    }

I find the optional label handy to keep different traces separate. Looking again, there’s an overload that accepts a category, so we’ll use that instead. So why might this be useful? Maybe we want to log the value assigned within an object initializer:

var q = new SPQuery() {
  Query = GetMyQuery().Debug("Query")
};

Rather than store the query string to a temporary variable or retrieve the property after it’s been set, we can just trace the value inline. Or consider a LINQ example:

var items = from SPListItem item in list.GetItems(q)
            let url = new SPFieldUrlValue(item["URL"] as string)
            where url.Url.Debug("URL").StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase)
            select new
            {
                Title = item.Title.Debug("Title"),
                Description = url.Description,
            };

Here we log all URLs that pass through, even the ones excluded from the result by the predicate. This would be much harder to implement efficiently without inline logging.

This technique works great for simple objects with a useful ToString(), but what about more complex objects? As has often been the answer lately, we can use higher-order functions:

    public static T Dbg<T, R>(this T value, Func<T, R> selector)
    {
        Debug.WriteLine(selector(value));
        return value;
    }

    public static T Dbg<T, R>(this T value, string category, Func<T, R> selector)
    {
        Debug.WriteLine(selector(value), category);
        return value;
    }

Now we can provide a delegate to trace whatever we want without affecting the object itself. For example, we can easily trace a row count for the DataView being returned:

public DataView GetResults()
{
    var myTable = GetDataTable();
    // Process data...
    return myTable.DefaultView.Dbg("Result Count", v => v.Count);
}

I could go on, but you get the idea.

PowerShell Filter

Finally, we can implement similar functionality in PowerShell using a filter with an optional scriptblock parameter:

filter Debug([scriptblock] $sb = { $_ })
{
  [Diagnostics.Debug]::WriteLine((& $sb))
  $_
}

PS > 1..3 | Debug { $_*2 } | %{ $_*$_ }
1
4
9

Which traces 2, 4, 6, as expected.

Update 4/19/2009: Changed functions to use category overloads. And another point to consider: if the value being traced could be null, selector should be designed accordingly to avoid NullReferenceException. There’s nothing worse than bugs introduced by tracing or logging.

SharePoint Disposal Wish List

I was almost off my SharePoint disposal kick when Jeremy Jameson had to pull me back in with this post. Resisting the temptation to rehash some stuff I’ve covered before, I thought it might be therapeutic to spend some time discussing what the dispose story should look like. I’m sure the API for WSS 4.0 is more or less locked at this point, but it still might be useful to frame how I think about ownership of these blasted IDisposables.

In my SharePoint fantasy world, the dispose story can be explained in four bullets:

  1. Use of a disposed object throws an exception; failures to dispose properly are logged.
  2. IDisposable references retrieved from an instance property are owned by the instance.
  3. IDisposable references retrieved from a constructor, method or collection indexer are owned by the developer and should always be disposed.
  4. IDisposable references from an enumerator are owned and disposed by the enumerator.

Let’s examine these a bit more closely.

1. Disposed = Invalid = Use is Exceptional; Discoverability = Good

The leaked object logging is already pretty good, but that’s more than made up for by the epic failure to actually close objects that have been closed. Fixing discoverability would make all other points a matter of convenience.

2. Instance Properties

An instance property suggests “mine”. My context’s Site, my site’s RootWeb, my feature’s Parent, etc. If something is “mine,” then I should be responsible for it. This behavior is already consistent with three exceptions:

SPWeb.ParentWeb

This property is tricky because the instance is shared for all consumers of the SPWeb (think SPContext.Web), but will not be cleaned up if the SPWeb is disposed and has no mechanism to notify the child that it has been disposed to null out the reference to it. So what to do? Well in accordance with my fantasy guidelines, there are two options, either of which would resolve the ambiguity:

  1. Leave ParentWeb as a property and require that the SPWeb dispose its parent as part of the clean-up process.
  2. Provide SPWeb.GetParentWeb() instead, returning a new SPWeb on each call that is owned by the developer.

Since GetParentWeb() can be implemented as an extension method, I guess I would prefer option 1.

SPList.ParentWeb

This property is almost fine, but for some reason has an edge case returns a new SPWeb (details here). It should be fine as a property, but that edge case needs to disappear. Why can’t it just return SPList.Lists.Web?

MOSS UserProfile.PersonalSite

This property returns a new SPSite on each call, so ideally it would be a method instead, perhaps GetPersonalSite. That seems much easier than having UserProfile implement IDisposable to facilitate cleanup of shared instance.

3. Constructors & Methods & Indexers, Oh My!

If properties are “mine”, then everything else is “yours”. Again, the vast majority of the API already fits this behavior. The few discrepancies:

SPControl.GetContextSite() & SPControl.GetContextWeb()

I believe these are the only methods that return IDisposables that SharePoint owns. MSDN clearly indicates that behavior, but for consistency the preferred usage (consistent with our fantasy guidelines) would be to use an SPContext’s Site and Web properties instead.

MOSS PublishingWeb

I’ve already discussed the semi-disposability of PublishingWeb, which just needs a few tweaks to fit nicely in my fantasy model:

  • Implement IDisposable! Close() is already implemented, just need the interface to take advantage of our languages’ using constructs.
  • I believe ParentPublishingWeb would be fixed if SPWeb.ParentWeb were disposed with the child. Alternatively, change to GetParentPublishingWeb and ensure that the returned PublishingWeb will close the internal SPWeb on dispose.
  • PublishingWebCollection.Add() is fine, but the indexer works in such a way that an internal SPWeb is created that is not cleaned up by PublishingWeb.Close(). I would consider this a bug in the current code base, which would naturally be fixed in my fantasy.

4. Enumerating Collections

This isn’t quite as simple as it would seem. When dealing with collections and enumerators, there are essentially two classes of operation:

  1. Enumerate over all or part of the collection and perform an operation. (LINQ Select, GroupBy, OrderBy)
  2. Enumerate over the collection to pick an object from the collection to return. (LINQ First, Last, ElementAt)

In my experience, the vast majority fall into the first category, including most of LINQ. These operations shouldn’t need to know that the objects being enumerated are IDisposable; it’s up to the enumerator to behave appropriately. Rather than sacrifice these many useful operations, I suggest that the enumerator should include proper disposal of the objects it creates—this is precisely what my AsSafeEnumerable() iterator does.

The second category can either be handled using for loops and indexers, which return objects that the caller must dispose, or through higher-order functions that allow dispose-safe operation on or selection from the desired element. But again, these seem to be the exception rather than the rule, and can be handled accordingly.

Wishful Thinking

The unfortunate reality is that most of these adjustments could never happen because breaking changes are generally frowned upon. But perhaps in framing our disposal thought process around some simple rules with documented exceptions, it may be easier to get things right without leaning on tools like SPDisposeCheck.

Posted in Object Model, SharePoint. Tags: , . Comments Off on SharePoint Disposal Wish List

Community Stuff, Apr 2009

First, thanks to the folks at Cedar Valley INETA for coming out to my PowerShell 101 talk earlier this month. The deck, scripts and demo transcript are available for download here. Among other things, we looked at a script to use System.Speech from PowerShell. The results were outstanding:

Recognized [0.2717747] “some of”
Recognized [0.2246611] “us in the all the rest of us are”
Recognized [0.302918] “the Mike Tyson > Microsoft software”
Recognized [0.4645212] “of Mike Tyson is”
Recognized [0.4163939] “this still undecided vote”
Recognized [0.3286791] “-Mike Tyson did not understand its electricity can”

I’m not sure what I was trying to say, but I’m pretty sure it wasn’t that. Thanks to Josh and Travis for the great work they’re doing with that up-and-coming group.

Next up is the Iowa SharePoint User Group on Apr. 1st with Corey Erkes:

SharePoint and Social Networking

We will explore how to use SharePoint for social computing that will power the next generation of business productivity. During the session we will highlight the following components and how they can be extended using customization, Codeplex and partner solutions:

  • MySites
  • Blogs
  • Wikis
  • Podcasting
  • Unified Communications

Details:

As usual, if you have ideas or requests for future IASPUG topics, please send them to info@sharepointia.com.

Then on Saturday, Apr. 4th, I’ll be presenting at Twin Cities Code Camp 6:

Introduction to F#

With Visual Studio 2010, F# will officially become a first-class citizen in the .NET development ecosystem. This session will explore functional programming, why it matters in an object-oriented world, and how F# bridges the gap. I will also discuss some lessons learned from using F# with OpenCV, an unmanaged computer vision library.

And finally on Tuesday, Apr. 7th, I’ll be at the inaugural meeting of the new Dubuque INETA presenting an overview of what’s new in Visual Studio 2008, .NET 3.5 and the language features of C# 3.0 and Visual Basic 9. Thanks to Elizabeth Groom for her hard work getting that group started.

Also, the next Iowa Code Camp is confirmed for May 2 at Kirkwood College in Cedar Rapids. The last two have been fantastic, so definitely looking forward to it.

Posted in Community. Tags: , , , , . Comments Off on Community Stuff, Apr 2009