SPWeb.AssociatedGroups.Contains Lies

While working on SPExLib (several months ago), I revisited this post, which presented a functional approach to a solution Adam describes here. Both posts include logic to add an SPWeb group association, which most simply could look something like this:

SPGroup group = web.SiteGroups[groupName];
if (!web.AssociatedGroups.Contains(group))
{
    web.AssociatedGroups.Add(group);
    web.Update();
}

While testing on a few groups, I noticed that the Contains() call lies, always returning false. This behavior can also be verified with PowerShell:

PS > $w.AssociatedGroups | ?{ $_.Name -eq 'Designers' } | select Name

Name
----
Designers

PS > $g = $w.SiteGroups['Designers']
PS > $w.AssociatedGroups.Contains($g)
False

Of course, it’s not actually lying—it just doesn’t do what we expect. Behind the scenes, AssociatedGroups  is implemented as a simple List<SPGroup> that is populated with group objects retrieved by IDs stored in the SPWeb‘s vti_associategroups property. The problem is that List<T>.Contains() uses EqualityComparer<T>.Default to find a suitable match, which defaults to reference equality for reference types like SPGroup that don’t implement IEquatable<T> or override Equals().

To get around this, SPExLib provides a few extension methods to make group collections and SPWeb.AssociatedGroups easier to work with and more closely obey the Principle of Least Surprise:

public static bool NameEquals(this SPGroup group, string name)
{
    return string.Equals(group.Name, name, StringComparison.OrdinalIgnoreCase);
}

public static bool Contains(this SPGroupCollection groups, string name)
{
    return groups.Any<SPGroup>(group => group.NameEquals(name));
}

public static bool HasGroupAssociation(this SPWeb web, string name)
{
    return web.AssociatedGroups.Contains(name);
}

public static bool HasGroupAssociation(this SPWeb web, SPGroup group)
{
    if (group == null)
        throw new ArgumentNullException("group");
    return web.HasGroupAssociation(group.Name);
}

public static void EnsureGroupAssociation(this SPWeb web, SPGroup group)
{
    if (web.HasGroupAssociation(group))
        web.AssociatedGroups.Add(group);
}

The code should be pretty self-explanatory. The name comparison logic in NameEquals() is written to align with how SharePoint compares group names internally, though they use their own implementation of case insensitivity because the framework’s isn’t good enough. Or something like that.

There should be two lessons here:

  1. Don’t assume methods that have a notion of equality, like Contains(), will behave like you expect.
  2. Use SPExLib and contribute other extensions and helpers you find useful. :)
Posted in Object Model, SharePoint. Tags: , . Comments Off

Functional Construction for ASP.NET Web Forms

System.Xml.Linq (a.k.a. LINQ to XML) introduces a nifty approach to creating XML elements called functional construction. I’m not entirely sure why they call it functional given that constructing an object graph is a decidedly non-functional task in the traditional sense of the word, but I digress.

Functional construction has three key features:

  1. Constructors accept arguments of various types, handling them appropriately.
  2. Constructors accept a params array of type Object to enable creation of complex objects.
  3. If an argument implements IEnumerable, the objects within the sequence are added.

If you haven’t seen it in action, I encourage you to take a look at the examples on MSDN and elsewhere—it really is pretty slick. This post will show how a similar technique can be used to build control trees in ASP.NET web forms (and probably WinForms with minimal adjustment).

Basic functional construction can be implemented using two relatively simple extension methods:

public static void Add(this ControlCollection @this, object content)
{
    if (content is Control)
        @this.Add((Control)content);
    else if (content is IEnumerable)
        foreach (object c in (IEnumerable)content)
            @this.Add(c);
    else if (content != null)
        @this.Add(new LiteralControl(content.ToString()));
}

public static void Add(this ControlCollection @this, params object[] args)
{
    @this.Add((IEnumerable)args);
}

We handle four cases:

  1. Control? Add it.
  2. Sequence? Add each.
  3. Other value? Add literal.
  4. Null? Ignore.

And our params overload just calls its arguments a sequence and defers to the other.

In the time-honored tradition of contrived examples:

Controls.Add(
    new Label() { Text = "Nums:" },
    "&nbsp;",
    from i in Enumerable.Range(1, 6)
    group i by i % 2
);

This would render “Nums: 135246″. Note that the result of that LINQ expression is a sequence of sequences, which is flattened automatically and converted into literals. For comparison, here’s an equivalent set of statements:

Controls.Add(new Label() { Text = "Nums:" });
Controls.Add(new LiteralControl("&nbsp;"));
foreach (var g in from i in Enumerable.Range(1, 6)
                  group i by i % 2)
    foreach (var i in g)
        Controls.Add(new LiteralControl(i.ToString()));

Hopefully seeing them side by side makes it clear why this new method of construction might have merit. But we’re not done yet.

Expressions, Expressions, Expressions

Many language features introduced in C# 3.0 and Visual Basic 9 make expressions increasingly important. By expressions I mean a single “line” of code that returns a value. For example, an object initializer is a single expression…

var tb = new TextBox()
{
    ID = "textBox1",
    Text = "Text"
};

… that represents several statements …

var tb = new TextBox()
tb.ID = "textBox1";
tb.Text = "Text";

That single TextBox expression can then be used in a number of places that its statement equivalent can’t: in another object initializer, in a collection initializer, as a parameter to a method, in a .NET 3.5 expression tree, the list goes on. Unfortunately, many older APIs simply aren’t built to work in an expression-based world. In particular, initializing subcollections is a considerable pain. However, we can extend the API to handle this nicely:

public static T WithControls<T>(this T @this, params object[] content) where T : Control
{
    if(@this != null)
        @this.Controls.Add(content);
    return @this;
}

The key is the return value: Control in, Control out. We can now construct and populate a container control with a single expression. For example, we could build a dictionary list (remember those?) from our groups:

Controls.Add(
    new HtmlGenericControl("dl")
    .WithControls(
        from i in Enumerable.Range(1, 6)
        group i by i % 2 into g
        select new [] {
            new HtmlGenericControl("dt")
            { InnerText = g.Key == 0 ? "Even" : "Odd" },
            new HtmlGenericControl("dd")
            .WithControls(g)
        }
    )
);

Which would render this:

Odd
135
Even
246

Without the ability to add controls within an expression, this result would require nested loops with local variables to store references to the containers. The actual code produced by the compiler would be nearly identical, but I find the expressions much easier to work with. Similarly, we can easily populate tables. Let’s build a cell per number:

Controls.Add(
    new Table().WithControls(
        from i in Enumerable.Range(1, 6)
        group i by i % 2 into g
        select new TableRow().WithControls(
            new TableCell()
            { Text = g.Key == 0 ? "Even" : "Odd" },
            g.Select(n => new TableCell().WithControls(n))
        )
    )
);

In a future post I’ll look at some other extensions we can use to streamline the construction and initialization of control hierarchies.

Using IDisposables with LINQ

Objects that implement IDisposable are everywhere. The interface even gets its own language features (C#, VB, F#). However, LINQ throws a few wrenches into things:

  1. LINQ’s query syntax depends on expressions; using blocks are statements.
  2. When querying a sequence of IDisposable objects, there’s no easy way to ensure disposal after each element has been consumed.
  3. Returning deferred queries from within a using statement is often desired, but fails spectacularly.

There are possible work-arounds for each issue…

  1. Put the using statement in a method (named or anonymous) that is called from the query. See also: Thinking Functional: Using.
  2. Use a method that creates a dispose-safe iterator of the sequence, like AsSafeEnumerable().
  3. Refactor the method to inject the IDisposable dependency, as shown in the first part of Marc’s answer here.

But, as you might have guessed, I would like to propose a better solution. The code is really complex, so bear with me:

public static IEnumerable<T> Use<T>(this T obj) where T : IDisposable
{
    try
    {
        yield return obj;
    }
    finally
    {
        if (obj != null)
            obj.Dispose();
    }
}

That’s it. We’re turning our IDisposable object into a single-element sequence. The trick is that the C# compiler will build an iterator for us that properly handles the finally clause, ensuring that our object will be disposed. It might be helpful to set a breakpoint on the finally clause to get a better idea what’s happening.

So how can this simple method solve all our problems? First up: “using” a FileStream object created in a LINQ query:

var lengths = from path in myFiles
              from fs in File.OpenRead(path).Use()
              select new { path, fs.Length };

Since the result of Use() is a single-element sequence, we can think of from fs in something.Use() as an assignment of that single value, something, to fs. In fact, it’s really quite similar to an F# use binding in that it will automatically clean itself up when it goes out of scope (by its enumerator calling MoveNext()).

Next, disposing elements from a collection. I’ll use the same SharePoint problem that AsSafeEnumerable() solves:

var webs = from notDisposed in site.AllWebs
           from web in notDisposed.Use()
           select web.Title;

I find this syntax rather clumsy compared with AsSafeEnumerable(), but it’s there if you need it.

Finally, let’s defer disposal of a LINQ to SQL DataContext until after the deferred query is executed, as an answer to the previously-linked Stack Overflow question:

IQueryable<MyType> MyFunc(string myValue)
{
    return from dc in new MyDataContext().Use()
           from row in dc.MyTable
           where row.MyField == myValue
           select row;
}

void UsingFunc()
{
    var result = MyFunc("MyValue").OrderBy(row => row.SortOrder);
    foreach(var row in result)
    {
        //Do something
    }
}

The result of MyFunc now owns its destiny completely. It doesn’t depend on some potentially disposed DataContext – it just creates one that it will dispose when it’s done. There are probably situations where you would want to share a DataContext rather than create one on demand (I don’t use LINQ to SQL, I just blog about it), but again it’s there if you need it.

I’ve only started using this approach recently, so if you have any problems with it please share.

Stylish Gears: Customizing SPLongOperation

A frequently-asked branding question is how to customize the “gear” page shown during an SPLongOperation. The short answer is “you can’t”; but that’s not entirely true. The operation can be slightly customized using its LeadingHTML and TrailingHTML properties, which are written directly to the response stream. Because they aren’t encoded, we can use one to inject some JavaScript into the page that can manipulate the DOM, insert a stylesheet, really do anything we want. It’s not an ideal solution, as there will be a brief moment where the page is shown in its original form before the script can execute, but I believe it’s about the best we can do without directly modifying 12\TEMPLATE\LAYOUTS\gear.aspx. SharePoint's Gear of War

As a quick proof of concept, here’s the source of an .aspx you can place in LAYOUTS to see a long operation page that uses the current theme:

<%@ Page Language="C#" %>
<%@ Import Namespace="Microsoft.SharePoint" %>

<script language="C#" runat="server">
  protected override void OnLoad(EventArgs e)
  {
    string themeUrl = SPContext.GetContext(this.Context).Web.ThemeCssUrl;
    using (SPLongOperation op = new SPLongOperation(this.Page))
    {
      StringBuilder sb = new StringBuilder();
      sb.Append(themeUrl+"</span> \n");
      sb.Append("    <script language=\"javascript\"> \n");
      sb.Append("      (function(){ \n");
      sb.Append("        var objHead = document.getElementsByTagName('head')[0]; \n");
      sb.Append("        if(objHead) { \n");
      sb.Append("          var objTheme = objHead.appendChild(document.createElement('link')); \n");
      sb.Append("          objTheme.rel = 'stylesheet'; \n");
      sb.AppendFormat("          objTheme.href = '{0}'; \n", themeUrl);
      sb.Append("          objTheme.type = 'text/css'; \n");
      sb.Append("        } \n");
      sb.Append("      })();");
      sb.Append("\n<"+"/script><span>");
      op.TrailingHTML = sb.ToString();
      op.Begin();

      System.Threading.Thread.Sleep(10000);
    }
  }
</script>

I use a StringBuilder because embedded scripts don’t play well with multi-line constants. In production, I would probably embed the script as a resource.

Here’s the result with the built-in Granite theme:
Granite-Themed SPLongOperation

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!

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
Follow

Get every new post delivered to your Inbox.