Inconvenient Silverlight Object Model vs. anonymous users


SharePoint 2010 ships with Silverlight Object Model that simplifies working with SharePoint data within Silverlight components. Thanks to the new object model you no longer have to create and deploy custom services to retrieve data from SharePoint. Out of the box the Silverlight Object Model encapsulates calling standard SharePoint WCF Services which makes it extremely easy for you as a developer to create Silverlight components that communicate with SharePoint. Although working with the Silverlight Object Model is pretty easy, there is one thing that you have to keep in mind while developing for anonymous users.

Using the Silverlight Object Model you can easily retrieve data from SharePoint. With just a few asynchronous calls you can retrieve data from a SharePoint list:

public partial class MainPage : UserControl
{
    public string SiteUrl { get; private set; }
    
    private ClientContext context;
    private Web web;
    private ListItemCollection items;

    public MainPage(string siteUrl)
    {
        if (String.IsNullOrEmpty(siteUrl))
        {
            throw new ArgumentNullException("siteUrl");
        }
    
        InitializeComponent();
        Loaded += new RoutedEventHandler(MainPage_Loaded);
        SiteUrl = siteUrl;
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        LoadItems();
    }

    private void LoadItems()
    {
        context = new ClientContext(SiteUrl);

        if (context != null && context.Web != null)
        {
            web = context.Web;
            context.Load(web, w => w.Lists);
            context.ExecuteQueryAsync(webSucceededCallback, failedCallback);
        }
    }

    private void failedCallback(object sender, ClientRequestFailedEventArgs args)
    {
        // exception handling goes here
    }

    private void webSucceededCallback(object sender, ClientRequestSucceededEventArgs args)
    {
        Dispatcher.BeginInvoke(() =>
        {
            List list = web.Lists.GetByTitle("MyList");
            CamlQuery query = new CamlQuery
            {
                ViewXml = "<View><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query></View>"
            };
            items = list.GetItems(query);
            context.Load(items);
            context.ExecuteQueryAsync(listSucceededCallback, failedCallback);
        });
    }

    private void listSucceededCallback(object sender, ClientRequestSucceededEventArgs args)
    {
        // do something with list items here
    }
}

The above code will work just fine. But as soon as you try to view your Silverlight component as an anonymous user you will get a JavaScript exception. Examining the response from the asynchronous call will show you something similar to:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json
Vary: Accept-Encoding
Server: Microsoft-IIS/7.5
SPRequestGuid: 26ba18ca-cab7-453d-b58d-46ab3f4f78f2
X-SharePointHealthScore: 5
X-Content-Type-Options: nosniff
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 14.0.0.4762
pubDate: Tue, 04 May 2010 06:16:21 GMT
Content-Length: 352

[
{
"SchemaVersion":"14.0.0.0","LibraryVersion":"14.0.4762.1000","ErrorInfo":{
"ErrorMessage":"The method \"GetItems\" of the type \"List\" with id \"{d89f0b18-614e-4b4a-bac0-fd6142b55448}\" is blocked by the administrator on the server.","ErrorValue":null,"ErrorCode":-2147024846,"ErrorTypeName":"Microsoft.SharePoint.Client.ApiBlockedException"
}
}
]

Does it seem like Silverlight Object Model doesn’t allow anonymous users to access SharePoint data?

The solution

Although the error message clearly states that the GetItems method has been disabled by the administrator there is little information about how to enable it. It turns out that the solution is really easy and can be done either through custom code (like a Feature Receiver of a Feature scoped to Web Application) or PowerShell.

It turns out that Client Object Model methods that may be accessed by anonymous users are stored in the SPClientCallableSettings.AnonymousRestrictedTypes property. By default the restriction looks as follows:

Default list of types restricted for anonymous users.

As you can see the SPList.GetItems method is among the restricted types.

In order to enable retrieving List Items by anonymous users you can call the following PowerShell code:

$wa = Get-SPWebApplication -Identity "http://sharepoint"
$wa.ClientCallableSettings.AnonymousRestrictedTypes.Remove([Microsoft.SharePoint.SPList], "GetItems")
$wa.Update()

The SPList.GetItems method will be removed from the restricted types and your Silverlight component will allow anonymous users to retrieve List Items from SharePoint.

List of restricted types after removing the SPList.GetItems method.

If you want to set the settings to their original state you can replace Remove with Add in the code above and the GetItems method will get restricted again.

Big thanks to Einar Otto Stangvik for the clue on how to solve this challenge.

Technorati Tags: SharePoint 2010,Silverlight

Others found also helpful: