Tag Archives: SharePoint

Uncategorized

PowerShell+SharePoint Quickie: Export List Data

I’m packaging up some work I did for a client in a set of SharePoint features, and some of the features include list instances. In this case, I needed to package up a list instance into feature xml so it could be deployed from the administrative web interface, but I didn’t have the list data in that format. I didn’t want to enter the data by hand, and there wasn’t an easy, readily-available tool to help extract the data in the format I needed. Enter PowerShell:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$site = New-Object Microsoft.SharePoint.SPSite("http://mysharepointsite")
$site.RootWeb.Lists["MyList"].Items |% { "`n  {0}`n  {1}`n", $_["ID"],$_["Title"] }

This spits out XML formatted for use in a <ListInstance> element.

Uncategorized

VSeWSS: Value does not fall within the expected range.

On occasion, particularly if you’re moving files around or working on the structure of your project inside Visual Studio 2008, you’ll try to deploy your SharePoint project using VSeWSS 1.3 (March 2009 CTP) and get the following error:

Value does not fall within the expected range.

It’s cryptic and unhelpful. What value? What expected range? Experience has taught me that VSeWSS can only be deblogged, not debugged.

Anyway, this error usually means there is a file listed in the solution (as in WSP solution, not Visual Studio solution) manifest that doesn’t exist on the filesystem. Maybe SVN sucks (it does), or maybe you clicked the wrong button. Head down that path and you’ll likely find the problem.

A dead obvious giveaway is shown in this image. ┬áThe little ‘hazard’ icon indicates a file included in the project is missing from the filesystem.

Uncategorized

Lambdas in data-binding expressions

For a recent project, I wrote a templated web part (similar to the Smart Part) to do a search on a custom list and display the results (all using AJAX updates made available by the UpdatePanel), and I found myself unable to accomplish what I needed to accomplish in data-binding expressions inline in the user control loaded by my web part. I needed to be able to do multiple steps to condition the bound data before rendering it (for example, splitting a single field into multiple distinct fields that should be rendered differently).

For example, one of the bound fields I needed to render was a string formatted like this:

"http://www.website.com/page.aspx, Name of the Website"

I needed to render this as a link. Obviously, it won’t directly render properly. It needed to be split, so it could be rendered something like this:

Name of the Website

For this simple example, you can do it all inline without lambdas by taking advantage of the ability to pass an array as a params parameter:

String.Format("{1}",
              ((SPListItem)Container.DataItem)["WebPage"]
               .ToString().Split(new string[] { ", " }, 
                                 StringSplitOptions.RemoveEmptyEntries))

However, for a more complex case in which the bound data needs conditioning that can’t be done inline, typically you would do your conditioning and rendering in server side code ((Of course, the term “server-side” here doesn’t imply that inline expressions are executed on the client – they aren’t. It’s just a way to distinguish between code organized into class libraries and inline expressions embedded into ASP.NET files, like user controls.)).

The problem with that is that you then have to write a bunch of methods that kind of pollute your other classes, and your logic is divided (some in the user control, some in a class). Enter lambdas.

Data-binding expressions are somewhat restrctive in that they can only evaluate DataBinder.Eval and DataBinder.Bind. DataBinder is the context of the expression. However, you can create a new context by writing an inline lambda, like this:

() => 
{
  string url = ((SPListItem)Container.DataItem)["WebPage"].ToString();
  string toks[] = url.Split(new string[] {", "},
                      StringSplitOptions.RemoveEmptyEntries);
  return String.Format("{1}", toks[0], toks[1]);
}

Now you can see more clearly what it is you’re doing, and as an added bonus, you can actually set breakpoints on each individual statement and inspect local variables (an option that’s unavailable with chained expressions).

There’s a problem, though. The result of this expression is a lambda, not a string. When the page is hit and the server tries to compile this, it may fail. Even if it didn’t, the rendered result would not be desirable ((the lambda’s .ToString() method would be called, and the result would be what the end-user would seee)). Somehow, we have to cause this method to be invoked.

My suggestion is to write a server-side method for invoking the lambda.

public delegate string DbExprDelegate();

public static string DbExpr(DbExprDelegate lambda)
{
  var obj = lambda.Invoke();
  return obj;
}

To get the type system to go along, you have to define a delegate type for the lambda. In my case, I knew I would be taking no arguments and returning no strings. For more complex cases you may be able to make good use of generics and type inference to write a more useful generalization. Since lambdas are implicitly convertible to compatible delegates, you can then use the static method DbExpr in your data binding expression to invoke the lambda. I defined DbExpr in my web part class, but I could have put it just it just about anywhere because my user control has no reference to the web part object that loads it, which requires my DbExpr to be static. In other contexts where data binding expressions are used, you may have references to instance objects in your context and may not need to make your DbExpr static.

Finally, we now have the plumbing we need to make the data binding expression work:

<%@ Assembly Name="MyAssembly, etc, etc." %>
<%@ Import Assembly="MyAssembly" Namespace="MyNamespace" %>
 
<%# 
MyWebPartControl.DbExpr(() => 
  {
    string url = ((SPListItem)Container.DataItem)["WebPage"].ToString();
    string toks[] = url.Split(new string[] {", "},
                              StringSplitOptions.RemoveEmptyEntries);
    return String.Format("{1}", toks[0], toks[1]);
  })
%>