Free Web Part – Security Aware Silverlight SharePoint Web Part With Auditing

Just want the code? :

**Tested In SharePoint 2007 & SharePoint 2010**

While working at a new SharePoint client, one of the issues I was made aware of was that for new development Silverlight was being leveraged across both the legacy SharePoint 2007 and newly staged SharePoint 2010 instance for custom applications. While this wasn’t a strict standard to maintain the application in accordance with potential ongoing maintenance making use of Silverlight was the best approach.

The being said, I went off and delivered a series of applications that were built on Silverlight, hosting them in the pretty much default manner using the built-in SharePoint 2010 facilities. However, there are two huge, noticeable gaps with this:

1) There is no way to audit application invocation / what .XAP files were being used I think this is kind of a drag. It makes more sense to maintain a collated list of all the Silverlight files being invoked in a SharePoint environment, which would immediately require a new type of host that would provide such a holistic view into the Silverlight / SharePoint environment.

2) Security Configuration Being Internally Managed It seemed that while there were ways to tap directly into the SharePoint OM and inject resultant queries into Silverlight code, such a generic application didn’t lend itself well to an ad-hoc configuration basis. That sounds terrible. Since the container for users in the environment is well defined (i.e. relying on SharePoint to provide that through user profiles, user information list, etc.) this code can be super generic.

Expanding on the aforementioned concepts, it is easy to grasp some baseline requirements that must be present for the new Silverlight application host to be successful.

For Auditing –

1) When a new .XAP file is invoked through the host, this information must be sent to a retrievable medium that is easy to view and access. So a SPList object should be leveraged.

2) For matrix-based SharePoint taxonomies, the host must be a site collection-by-site collection basis since divisions while have different site collection administrators that are responsible for collating and analyzing the information. Rolling this information up can simply lean on baked-in CQWP features or a custom rollup.

3) The information collected should be:

a. .XAP invoked
b. SPWeb Title
c. Page (SPItem) Title
d. Full (Absolute) URL to the hosting page
e. Last Modified Date (if the WebPart is ever placed in edit more).

4) Auditing has to be dynamic in the sense that if the WebPart is modified, this event is recorded so that the information does not grow stale and unusable.

5) An email should be sent to a user specified in the host when a new file is invoked.

6) All required content placeholders should be generated automatically.

For Security –

1) Simply put, security settings on the corresponding audit entries should naturally flow to the Silverlight application so that a developer can easily read the past in roles. Since an SPListItem is a SecurableObject, it makes sense to just compartmentalize the permissions corresponding between Silverlight and the SPListItem.

2) Since permissions set on the SPListItem will translate to those read from the Siverlight application, an event receiver to do group membership checks for configured administrators should be implemented.

3) The roles and current user should be available as parameters to the Silverlight application.

The code is deployed as a regular good ol SharePoint Feature:

At first the site collection will have no lists:

Activate The Feature:

A WebPart Instances List Will Be Generated At The Root Of The Site Collection:

These columns will be provided by a specialized content type, while the default item content types is removed:

The Instance Content Type is programatically created by the feature (select for a larger image):

The event receiver to protect unauthorized changes is wired in the same method:

Each Of The Items Is Represented As A WebPartIntance Type:

Each Of these values is hydrated using save methods of SPListItem objects:

And at the end of the day, the parameters are sent to the developer to consume (select for a larger image):

That’s a pretty good overview of the holistic application architecture. From an interface perspective, the first thing the WebPart is going to execute before performing any auditing events is check whether proper properties have been set (select for a larger image):

This is simply indicating that a Silverlight container and corresponding have not yet been selected:

The files themselves are trimmed according to silverlight extensions (select for a larger image):

Once all the requisite properties are set, you will see your Silverlight files running:


Fix Unhandled Error in Silverlight 2 Application Invalid cross-thread access error

Had a support call from a client today regarding a problem them were running into with Client OM access from a Silverlight application. The exact error was “Invalid cross-thread access”. Sitting down with the developer at the site I determined that this problem can be caused by two issues:

1) Your XAP is not copied into the right location. It is supposed to go into the 14 hive ClientBin directory under LAYOUTS. If the XAP is not present, this error can occur.

2) Objects in code and not being loaded correctly (this turned out to be the primary issue for my particular problem). Consider the following simply ListItem update code:

private void UpdateData()
ClientContext clientContext = new ClientContext(“url”);
Web web = clientContext.Web;
ListCollection listCollection = web.Lists;
list = listCollection.GetByTitle(“TestList”);
ListItem li = list.GetItemById(1);
li[“Title”] = “My new item”;
clientContext.ExecuteQueryAsync(onQuerySucceeded, onQueryFailed);

private void onQuerySucceeded (object sender, ClientRequestSucceededEventArgs args)
// I am not displaying show ShowMessage, but assume that it writes the list title to standard output
UpdateUIMethod updateUI = ShowMessage;

private void onQueryFailed (object sender, ClientRequestFailedEventArgs args)

Now, looking back at the error, what’s missing in the above code is the load! The objects will not be initialized with this code, which can cause that particular error.
To fix it, include the load, such as (fully qualified instantiation demoed, you would obviously use your own object conventions):
list => list.Title);
before executing the query, and the error should go away!


Considerations When Using TFS for SharePoint And Silverlight Development

During testing of my recent TFS migration we found a small issue with a SharePoint Application Page build that had some embedded Silverlight in it where the ClientBin directory was not being created by TeamBuild.

The error looks similar to the following:

MSBuild\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets(60,3): error MSB3021: Unable to copy file “ClientBin\Base.Silverlight..xap” to “\“. Could not find a part of the path ‘ClientBin\.xap’.

So why does this happen? There could be a couple reasons you might be running into this particular error, the largest of which is the default settings of TFS not checking in the XAP files. Which doesn’t make a ton of sense. Also, you will generally run into this error when a Siliverlight project is renamed and its parent directory is renamed. Which of these causing the error will determine the appropriate resolution path.

If you are running into this because you think you are hitting the renaming error, then the easiest way to fix it is to unload the project, edit .csproj, and correct the values in the tag. After you perform a check-in and start a build the error will go away. If you are not entirely sure why it is happening and the aforementioned renaming doesn’t sound like your issue, then you can implement a couple of other things to get around the problem.

Firstly, change the referring Content item in the xap file:

.xap” Condition=”$(IsDesktopBuild) != true” />

Following, in the AfterDropBuild Target, execute a manual copy of the xap to the _PublishedWebsites folder: