January 2010 - Posts

One misconception I have heard is that SharePoint 2010 is completely based on Silverlight.  While SharePoint does use Silverlight now in various places, I would say most of it is still based upon regular ASP.NET pages.  I haven’t seen anything that actually requires Silverlight yet, but it does make things prettier when you have it.  This is just a brief overview of some things you might see.  For example, one of my favorite new things is the Create page.  If you don’t have Silverlight installed, you get something that looks like this.

CreatePage

As you can see it looks a lot like the traditional Create page in previous versions of SharePoint.  However, one thing you might notice that’s new on this page is the Improve the Creation Experience - Install Microsoft Silverlight link.  It gives you a link to install it and the next time you go to the create page, you get a modal window, that looks like this.

CreatePageSilverlight1

As you can see the experience is much nicer.  When you hover over each time, you get an effect and all that pretty stuff.  You have various ways to filter and categorize what you can create as well.  If you are worried about your settings when creating a site, don’t worry they are neatly tucked away under the More Options button.  Here is what that looks like.

CreatePageSilverlight2

This is just one place where things have changed.  You are going to find Silverlight in other areas as well of course.  The most notable areas would be the PowerPoint preview in the FAST search results as well as in Office Web Apps.  I’m going to talk about Office Web Apps more soon, but the main thing I will point out is that they do not require Silverlight.  So if you are editing a Word Document directly in the browser, you can do that with just HTML and JavaScript.  Now if you do have Silverlight, you gain some things such as how well the document zooms, but for the most part the experience is largely the same.

The last thing to mention is that there is a Silverlight web part included now (which I am sure you have already heard about).  This is nice because it makes it easy to include your own Silverlight applications without having to rely on third party web parts or writing your own.

When I get an error, I like to blog about it.  Especially when the error gives you no useful information whatsoever.  Now, you can get the above error in a variety of ways, but the one I am going to discuss today is when using SPQuery.  I inherited some code that had some CAML queries in it and I could not figure out what the cause was at first.  When I called SPList.GetItems(SPQuery), I would receive something like the following.

Microsoft.SharePoint.SPException was unhandled by user code
  Message="Cannot complete this action.\n\nPlease try again."
  Source="Microsoft.SharePoint"
  ErrorCode=-2147467259
  StackTrace:
       at Microsoft.SharePoint.Library.SPRequest.GetListItemDataWithCallback(String bstrUrl, String bstrListName, String bstrViewName, String bstrViewXml, SAFEARRAYFLAGS fSafeArrayFlags, ISP2DSafeArrayWriter pSACallback, ISPDataCallback pPagingCallback, ISPDataCallback pSchemaCallback)
       at Microsoft.SharePoint.SPListItemCollection.EnsureListItemsData()
       at Microsoft.SharePoint.SPListItemCollection.get_Count()
       at Samson.P2S.SharePoint.Services.Synchronization.P2S_SynchronizationService.<>c__DisplayClass6.<GetInventoryChecklist>b__4() in C:\Projects\SamsonTFS\P2S\P2S_V0\Samson.P2S.SharePoint.Services.Synchronization\P2S_SynchronizationService.asmx.cs:line 166
       at Microsoft.SharePoint.SPSecurity.CodeToRunElevatedWrapper(Object state)
       at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.<RunWithElevatedPrivileges>b__2()
       at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
  InnerException: System.Runtime.InteropServices.COMException
       Message="Cannot complete this action.\n\nPlease try again."
       Source=""
       ErrorCode=-2147467259
       StackTrace:
            at Microsoft.SharePoint.Library.SPRequestInternalClass.GetListItemDataWithCallback(String bstrUrl, String bstrListName, String bstrViewName, String bstrViewXml, SAFEARRAYFLAGS fSafeArrayFlags, ISP2DSafeArrayWriter pSACallback, ISPDataCallback pPagingCallback, ISPDataCallback pSchemaCallback)
            at Microsoft.SharePoint.Library.SPRequest.GetListItemDataWithCallback(String bstrUrl, String bstrListName, String bstrViewName, String bstrViewXml, SAFEARRAYFLAGS fSafeArrayFlags, ISP2DSafeArrayWriter pSACallback, ISPDataCallback pPagingCallback, ISPDataCallback pSchemaCallback)
       InnerException:

The cause is actually simple.  My CAML query was malformed.  Specifically my where clause was not nested properly.  The previous developer put three conditions in an and clause and that simply does not work.  A COM exception though?  Really? Wouldn’t it have just been better if it validated the query first and gave us a nice error message such as the following?

CAML query is malformed.

That would be too nice I guess.  Anyhow, if you get this when querying, start looking at that query.  While, I am here, I’ll remind you if you copy the query from CAML Query Builder, to remove the Query element.  If you can’t figure it out and first, go back to the CAML query building tool of your choice and start executing the query there and comparing it to the one you have.  You should be up and running in no time.

with 5 comment(s)
Filed under: , ,

What I really like about SharePoint 2010 is all of the new ways we can get at list data.  You can always use the Client Object Model, Linq to SharePoint, or the existing object model, but one neat new way to get at list data is with listdata.svc.  ListData.svc provides a way of getting information from a list (or lists using joins) using REST.  What you end up with is a nice RSS feed of list data, that you can consume with whatever client you would like.  You can construct URLs in various manners to get specific records, do joins, or perform simple queries.  I won’t go through everything that you can do with it today, but I’ll point you towards resources to do the more advanced things.

When you are getting started, the first thing you want to do is check and see if you have ListData.svc up and running.  Like any SharePoint web service, it’s located in the _vti_bin folder of any existing site, so it will work with items relative to that site.  Here is what a typical URL might look like.

http://<sharepoint-server>/_vti_bin/ListData.svc

Try hitting that URL on your SharePoint 2010 server and see if it works.  There is a good chance that you will get a 404 error.  This happened to me, so I did some searching and found Rob Garret’s post stating to go out and install ADO.NET Data Services 1.5 CTP 2.  There are a few choices, but I have seen others recommend you go with the runtime only.  I had issues installing the full package.  Once you have it installed, it still didn’t work for me, so I rebooted my server and everything worked fine when it booted back up.  My guess is you probably could just reset IIS though.

Once you have a working ListData.svc, hitting it you should get results like this. 

ListDataSvcNoParameters

You get an XML document of all lists available to be queried.  If you notice the href on each collection it gives you an idea of how you can construct subsequent URLs to get data.  In today’s example, we’re going to work with a simple task list.  We’ll look at the various ways we can get data from this list.

ListDataSvcTaskList

To get the data for this list via REST we simply just add the list name to the URL.  In my case the name of the list is called Tasks.  Here is what the URL would look like.

http://<sharepoint-server>/_vti_bin/ListData.svc/<ListName>

In my case:

http://sp2010/_vti_bin/ListData.svc/Tasks

Here is what the results look like.

ListDataSvcTasksAll

As you can see we get an RSS feed and this is how Internet Explorer renders it.  However, if we look at the actual XML of the feed, we’ll find that we get quite a bit of data back about the list.  Here is a snippet of the XML.

<feed xml:base="http://sp2010/_vti_bin/ListData.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">

  <title type="text">Tasks</title>

  <id>http://sp2010/_vti_bin/ListData.svc/Tasks</id>

  <updated>2010-01-21T19:21:27Z</updated>

  <link rel="self" title="Tasks" href="Tasks" />

  <entry m:etag="W/&quot;1&quot;">

    <id>http://sp2010/_vti_bin/ListData.svc/Tasks(1)</id>

    <title type="text">Test 1</title>

    <updated>2010-01-21T09:26:51-06:00</updated>

    <author>

      <name />

    </author>

    <link rel="edit" title="TasksItem" href="Tasks(1)" />

    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Attachments" type="application/atom+xml;type=feed" title="Attachments" href="Tasks(1)/Attachments" />

    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Predecessors" type="application/atom+xml;type=feed" title="Predecessors" href="Tasks(1)/Predecessors" />

    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Priority" type="application/atom+xml;type=entry" title="Priority" href="Tasks(1)/Priority" />

    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Status" type="application/atom+xml;type=entry" title="Status" href="Tasks(1)/Status" />

    <category term="Microsoft.SharePoint.DataService.TasksItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

    <content type="application/xml">

      <m:properties>

        <d:ID m:type="Edm.Int32">1</d:ID>

        <d:ContentTypeID>0x01080085FF0E1548B7414787A693232497B24E</d:ContentTypeID>

        <d:ContentType>Task</d:ContentType>

        <d:Title>Test 1</d:Title>

        <d:Modified m:type="Edm.DateTime">2010-01-21T09:26:51</d:Modified>

        <d:Created m:type="Edm.DateTime">2010-01-21T09:26:51</d:Created>

        <d:CreatedByID m:type="Edm.Int32">1</d:CreatedByID>

        <d:ModifiedByID m:type="Edm.Int32">1</d:ModifiedByID>

        <d:Owshiddenversion m:type="Edm.Int32">1</d:Owshiddenversion>

        <d:Version>1.0</d:Version>

        <d:Path>/Lists/Tasks</d:Path>

        <d:PriorityValue>(2) Normal</d:PriorityValue>

        <d:StatusValue>In Progress</d:StatusValue>

        <d:Complete m:type="Edm.Double" m:null="true" />

        <d:AssignedToID m:type="Edm.Int32" m:null="true" />

        <d:TaskGroupID m:type="Edm.Int32" m:null="true" />

        <d:Description>&lt;div&gt;Test 1 Task&lt;/div&gt;</d:Description>

        <d:StartDate m:type="Edm.DateTime">2010-01-21T00:00:00</d:StartDate>

        <d:DueDate m:type="Edm.DateTime" m:null="true" />

      </m:properties>

    </content>

  </entry>

As you can see in the content element, we can see the various site columns on a particular list item.  Of course, there is more we can do with REST than just view everything in a list.  If you want a specific item, you can use parenthesis and specify an indexer.  Note that it is unit-indexed, not zero-indexed.

http://<sharepoint-server>/_vti_bin/ListData.svc/<ListName>(<Index>)

In my case:

http://sp2010/_vti_bin/ListData.svc/Tasks(3)

However, when you do this, Internet Explorer will give you an error that it cannot display this feed.

ListDataSvcTaskListIndexerIeError

Not to worry though, if you view source, you still have a working XML document.  It will pretty much look like the one above minus the initial feed information.  You can take the query above and go one step further.  Say, you just want to know the status for a specific task (note that the site column is actually called StatusValue here), you can simply add it to the URL like this.

http://<sharepoint-server>/_vti_bin/ListData.svc/<ListName>(<Index>)/(<Field>)

In my case:

http://sp2010/_vti_bin/ListData.svc/Tasks(3)/StatusValue

You’ll get an even simpler XML document that looks like this.  It will create an element named after whichever site column you passed to it.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>

<StatusValue xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">Completed</StatusValue>

The last thing I will cover is simple queries.  You can do this with $filter.  There are a number of operators you can use here, but the one I will start with today is eq (or equals).  For example, say I want to see all tasks that are completed, I would use a URL like this.  Put any literals inside quotes.

http://sp2010/_vti_bin/ListData.svc/Tasks?$filter=StatusValue eq 'Completed'

This returns results that look like this and of course the content element in the XML has the complete data on each list item returned.

ListDataSvcTaskListQuery

You can also use various other types of predicates, such as ne, gt, ge, lt, le, and, or, not, etc.  What each one does is probably pretty obvious, but if its not take a look at this MSDN reference for more information on the various filters and parameters you can use.  Skip the code stuff at the begging and scroll down a bit to find the good stuff.  This is a good start to working with REST in SharePoint, but this really is just the tip of it.  What you are learning here isn’t really just specific to SharePoint but it applies to anything you do with ADO.NET Data Services, so it might be useful elsewhere later.

One thing I will point out is that I was not able to use this with an external list.  I am guessing this is by design (which sucks), but it doesn’t look like it’s going to work.  Of course, my install could just be broken or this could be subject to change.

I saw this feature in Visual Studio again the other day and honestly I had kind of forgotten about it.  After discussing it with some colleagues, most of them didn’t even know the feature existed.  What I am talking about is the ability to create a link between files in Visual Studio.  What this allows you to do is actually create a link to a file instead of just making a copy.  Now, I don’t want to get into a discussion of why you would never want to do this or how this is not a proper way to implement code reuse.  Keep in mind though that you can use it to link other types of non-code files such as an XML file.  However, for today’s purpose, I’m just going to link a class into another project.  Consider my following example with two class libraries. I want to reuse Class1.cs inside ClassLibrary2.

FileLinkingSolution

I have a simple class that looks like this.

using System;

 

namespace ClassLibrary1

{

    public class Class1

    {

        public Class1()

        {

        }

 

        public void DoSomething()

        {

            int x = 5;

        }

    }

}

This class clearly has so much valuable code in it that I have to reuse it in ClassLibrary2, but not make a reference to ClassLibrary2.  This is where the Add as Link functionality comes in.  The process is simple, using the Add Existing Item menu on the project’s context menu.  Navigate to the existing item in the other class library and then make note of the arrow next to the Add button, click on it and choose Add as Link instead.

FileLinkingAddExistingItem

Once you do that you will have a link to the file in your other class library.  You can open it and edit it as normal from the linked location, but it will actually edit the file link.  You can tell it is linked in Solution Explorer by the icon.

FileLinkingSolutionLinkIcon

Notice the link icon on Class1.cs in ClassLibrary2.  If you click on the linked file, you can see the path to the file it has linked in the properties (although its cut off here in my screenshot).

FileLinkingProperties

Once you are done here, you can make changes to the file from either class library and the original file gets updated.  Keep in mind though, if you delete the original file, the link will be broken and you will get an error when trying to view any links.  I don’t know how useful this feature will be to all of you, but I think there is a time and place for everything.  I can definitely see this being useful in some cases.  This isn’t a new feature either.  I think its been around since at least Visual Studio 2003, but I could be wrong.

One new feature in SharePoint 2010 is the ability to version and upgrade features.  I haven’t seen a lot of people talking about it yet, so I thought I would take a few minutes to talk about it today.  It’s an interesting new feature and I’ll be curious to see how much people use it and when.  The versioning aspect of features is interesting, but specifically what we’ll be talking about today are what kinds of things we can do when we perform a feature upgrade.  Unfortunately, by the time you read all of this, it will probably leave you with more questions than you started with.  You will probably be asking yourself a lot of questions like “well, what happens when I upgrade a feature and it has X in it?”.

The first thing to know is that SharePoint 2010 makes use of the Version attribute on the Feature element now.  We can then use this version to execute code or do various things in an element manifest.  This is also an easy way to add a new site column to a content type which we’ll talk about in a bit.  It all starts with the UpgradeActions element in your feature.xml.  It takes a ReceiverAssembly and ReceiverClass attribute just like the Feature element takes.  Here is what it would look like.

<UpgradeActions ReceiverAssembly="MyFeatureReceiver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3e1b35c83d6e53f4"

  ReceiverClass="MyFeatureReceiver.MyFeatureReceiver">

If you’re not going to be executing custom upgrade action code, you can leave that part out the assembly.  You can then optionally add a VersionRange that takes BeginVersion and EndVersion attributes.  You can specify multiple VersionRange elements to handle upgrades across multiple versions with one file.  You can then specify what you want to occur on the feature upgrade. 

<VersionRange BeginVersion="1.0.0.0" EndVersion="1.9.9.9">

One of the most common things you can do is to specify a separate element manifest file which deploys various things to SharePoint when the solution is upgraded.  This file will have the same syntax as any other elements.xml file you have used.  Here is what that would look like.

<ApplyElementManifests>

  <ElementManifest Location="WebPart1\UpgradeManifest.xml"/>

</ApplyElementManifests>

Another thing you can do is rename a file.  So if you deployed a file called default.aspx and now you want to be called default2.aspx, you can have your upgrade make the change.  I have no idea if it would actually update anything that references the file.  I would guess not, but it’s there to try out if you ever need it.

<MapFile FromPath="OldFilename.aspx" ToPath="NewFilename.aspx" />

One thing, that is pretty interesting is the ability to add new site columns to an existing content type.  The syntax is pretty similar and it will even push down changes to content types that inherit from it.  Just specify the ContentTypeId, FieldId, and whether or not you want it to PushDown

<AddContentTypeField ContentTypeId="0x010100F15ADB2FA333AD49848E7E01BC79C9750202"

                     FieldId="{b63c6371-f774-451d-b4fb-5679625fafd5}"

                     PushDown="TRUE" />

The last thing to mention is that, you can execute custom code when a feature is upgrading.  If you have some complex upgrade logic this is the way to go.  It works by overriding the FeatureUpgrading event handling method.  It passes the UpgradeActionName and an IDictionary of parameters.  I’m not going to go into what the code looks like on a feature upgrade today, but I will cover it in a future post soon.  Here is what a complete UpgradeActions element might look like in your feature.xml.

<UpgradeActions ReceiverAssembly="MyFeatureReceiver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3e1b35c83d6e53f4"

  ReceiverClass="MyFeatureReceiver.MyFeatureReceiver">

  <VersionRange BeginVersion="1.0.0.0" EndVersion="1.9.9.9">

    <ApplyElementManifests>

      <ElementManifest Location="WebPart1\UpgradeManifest.xml"/>

    </ApplyElementManifests>

    <AddContentTypeField ContentTypeId="0x010100F15ADB2FA333AD49848E7E01BC79C9750202"

                         FieldId="{b63c6371-f774-451d-b4fb-5679625fafd5}"

                         PushDown="TRUE" />

    <CustomUpgradeAction Name="MyCustomUpgradeAction">

      <Parameters>

        <Parameter Name="Parameter1">Some Value</Parameter>

        <Parameter Name="Parameter2">Some Other Value</Parameter>

      </Parameters>

    </CustomUpgradeAction>

    <MapFile FromPath="OldFilename.aspx" ToPath="NewFilename.aspx" />

  </VersionRange>

</UpgradeActions>

I’ll be really curious to see how and if people use feature upgrades.  It definitely seems like it can be useful, but I don’t know if I will want to have my feature broken out into a bunch of different manifest files when I start having lots of upgrades.