| Subcribe via RSS

Silverlight Host Web Part

October 4th, 2008 | No Comments | Posted in SharePoint, Silverlight

Description
Lot’s of people start developing Silverlight applications these days and I asked myself: Why not host these applications in SharePoint?

I developed a very simple web parts that loads a silverlight application file (.xap) stored within a document library and runs it within its viewspace.

Requirements
Before you can deploy and use the web part in your SharePoint farm you have to complete the following tasks:

  • 1. Install Silverlight 2 Beta 2 on the server.
  • 2. Copy the file System.Web.Silverlight.dll to the GAC (The file is usually located in C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Server)
  • 3. Make neccessary adjustments to the web.config. This step is quite complex so I recommend you watch this screencast from Patrick Tisseghem and follow it step by step.
  • 4. Add this MIME type mapping to the IIS Website: .xap -> application/x-silverlight-2-b2

If you want to recompile the source code of this web part you have to install Visual Studio 2008 and the Silverlight Tools for VS 2008 and the Visual Studio Extensions for SharePoint 1.2.

Download, Deploy and Use

  • 1. Download the wsp file (setup.bat included) and install the web part.
  • 2. Download this sample .xap file that you can show within your silverlight web part.
  • 3. Ensure that the feature “Silverlight 2 Beta 2 Host Web Part Feature” is activated within the site collection.
  • 4. Upload the .xap file into a document library.
  • 5. Edit a page and add the web part “Silverlight 2 Beta 2 Host Web Part” to a web part zone.

  • 6. Now edit the web part properties and set the property “XAP URL” with the url to the xap file.

  • 7. Exit edit mode and refresh the page. The web part should show the silverlight application now.

Source Code

You can download the web part project here.

The first step is to ensure that a script manager exists on the page.

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    ScriptManager sm = ScriptManager.GetCurrent(this.Page);
    if (sm == null)
    {
        sm = new ScriptManager();
        Controls.AddAt(0, sm);
    }
}

The second step is to provide a web part property to consume a URL to the .xap file.

[WebBrowsable(true)]
[Personalizable(PersonalizationScope.Shared), Category("Silverlight")]
[FriendlyName("XAP URL")]
[Description("URL to XAP file")]
public string XapUrl
{
    get { return m_xapUrl; }
    set { m_xapUrl = value; }
}
protected string m_xapUrl = string.Empty;

The third step is to create a Silverlight control and load the Silverlight application into it:

protected override void CreateChildControls()
{
    base.CreateChildControls();
 
    try
    {
        if (!string.IsNullOrEmpty(XapUrl))
        {
            Silverlight ctrl = new Silverlight();
            ctrl.ID = this.ID + "_" + "SilverLightControl";
            ctrl.Source = XapUrl;
            ctrl.Width = new Unit(100, UnitType.Percentage);
            ctrl.Height = new Unit(m_controlHeight, 250);
            Controls.Add(ctrl);
        }
        else
        {
            Label lbl = new Label();
            lbl.Text = "Provide the url to a .xap file.";
            lbl.ID = this.ID + "_" + "LblMessage";
            Controls.Add(lbl);
        }
    }
    catch (Exception ex)
    {
        Label lbl = new Label();
        lbl.Text = string.Format("Error: " + ex.Message);
        lbl.ID = this.ID + "_" + "LblMessage";
        Controls.Add(lbl);                
    }
}

Have a nice Silverlight day,
Alex

Tags: , ,

Best practices: SharePoint Timer Jobs

August 18th, 2008 | 1 Comment | Posted in SharePoint

Part 1: Experiences and bad practices

I’ve developed a couple of SharePoint Timer jobs during the last months and gained a lot of experiences with deploying, configuring, debugging and updating them. Adding your code directly into a SharePoint timer job has many disadvantages:

Configuration

Timer jobs are run from the SharePoint Timer Service also known as owstimer.exe. You can place a owstimer.exe.config and add your configuration settings here. It serves as a shared app.config for all timer jobs. If you modify the configuration file you have to restart the timer job service to let the changes take effekt.

The config file is not designed to be used for timer job configuration so it doesn’t exist after you installed SharePoint. You have to create it on your own.

There are some alternative possibilities like custom defined xml files stored in a file at a defined location on the hard disc. Andrew Connel describes some ways to configure SharePoint timer jobs at MSDN. In my opinion none of them are simple to implement and nice to handle like a web.config or app.config.

Degbugging

To debug a timer job you have to attach the debugger to the owstimer.exe process, set breakpoint and wait until your timer job is executed. This could take minutes for each debugging session.

Deployment and redeployment

The deployment of a timer job is easy stuff if you have a visual studio template doing the dirty work for you. However, redeploying a solution means that you have to restart the SharePoint Timer Service and IIS what means session reset to all connected users.

Part 2: Extract code from timer job to web service

A default timer job is implemented like this:

Your code is inside the timer job and accessing your SharPoint using the API.

If you are going to write many lines of code your timer job you have a huge potential for error and you will need a couple of debugging sessions to fix all errors. Since debugging timer jobs take much time this doesn’t seem to be the best way implementing timer jobs.

Here’s my idea: Extract your code from the timer job into a web service.

In this scenaro your timer job has just those lines of code needed to call the web service. The configuration parameters of this timer job is quite short - just the URL of your webservice. On single server farms you could reference your web service using “localhost:portxy” and do not need a configuration for this. If you need a configuration option you could chose on of the alternatives described by Andrew Connell at MSDN.

Using a web service has some big advantages:

Configuration file

You can deploy a web.config file and put as many configurations in it as you wish and do not have to worry about affecting other job configurations. If you modify the web.config file you do not have to restart any services or the IIS.

Deployment

You can deploy and redeploy your web service without having to restart the SharePoint timer service or IIS.

Testing

You can write your own test client to call your web service whenever you want. You don’t have to wait until the timer service runs your code.

External job engine

If you have an external job engine like Control-M you can forego timer jobs and let the external job engine call your web servce. In this case you do not need the owstimer.exe.config anymore.

Security considerations

A web service accessing the SharePoint with administration rights adds a point of attack. Only the persons or service accounts that use the web service should be allowed to call the service.

Tags:

Reorder SharePoint list fields from code

July 19th, 2008 | 1 Comment | Posted in SharePoint

There’s no function in the SharePoint API to reorder the fields of a SharePoint list. You have to make use of the ProcessBatchDate from the SPWeb class.

/// <summary>
/// This function reorders the fields in the specified list 
/// programmatically as specified by the firstFields parameter.
/// The fields not included in the firstFields list will be
/// added to the list.
/// </summary>
/// <param name="list">The SPList object to update</param>
/// <param name="firstFields">A generic list of SPField containing the
/// first fields in the order to be displayed.</param>
public void ReorderField(SPList list, List firstFields)
{
  List<SPField> fields = new List<SPField>();
 
  for (int i=0; i<firstFields.Count; i++)
  {
    fields.Add(firstFields[i]);
  }
 
  foreach (SPField field in list.Fields)
  {
    if (!fields.Contains(field))
    {
      fields.Add(field);
    }
  }
 
  StringBuilder sb = new StringBuilder();
 
  XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(sb));
  xmlWriter.Formatting = Formatting.Indented;
 
  xmlWriter.WriteStartElement("Fields");
 
  for (int i=0; i&lt; fields.Count; i++)
  {
    xmlWriter.WriteStartElement("Field");
    xmlWriter.WriteAttributeString("Name", fields[i].InternalName);
    xmlWriter.WriteEndElement();
  }
 
  xmlWriter.WriteEndElement();
  xmlWriter.Flush();
 
  using (SPWeb web = list.ParentWeb)
  {
    ReorderFields(web, list, sb.ToString());
  }
}
 
/// <summary>  
/// This function reorders the fields in the specified list 
/// programmatically as specified by the xmlFieldsOrdered parameter  
/// </summary>  
/// <param name="web">The SPWeb object containing the list</param>
/// <param name="list">This function reorders the fields in the 
/// specified list</param>
/// <param name="xmlFieldsOrdered">A string in XML-format specifying the 
/// field order by the location within a xml-tree</param> 
private void ReorderFields(SPWeb web, SPList list,
  string xmlFieldsOrdered)
{
  try
  {
    string fpRPCMethod = @"<?xml version=""1.0"" encoding=""UTF-8""?>  
	<Method ID=""0,REORDERFIELDS"">  
	<SetList Scope=""Request"">{0}</SetList>  
	<SetVar Name=""Cmd"">REORDERFIELDS</SetVar>  
	<SetVar Name=""ReorderedFields"">{1}</SetVar>  
	<SetVar Name=""owshiddenversion"">{2}</SetVar>  
	</Method>";
 
      // relookup list version in order to be able to update it
      list = web.Lists[list.ID];
 
      int currentVersion = list.Version;
 
      string version = currentVersion.ToString();
      string RpcCall = string.Format(fpRPCMethod, list.ID,
        SPHttpUtility.HtmlEncode(xmlFieldsOrdered), version);
 
      web.AllowUnsafeUpdates = true;
      web.ProcessBatchData(RpcCall);
    }
    catch (System.Net.WebException err)
    {
      // TODO: Log this exception according your exception
      // handling policies.
      Console.WriteLine("WARNING:" + err.Message);
    }
}
Tags: , ,

Getting started with custom SharePoint Event Receivers

July 18th, 2008 | 5 Comments | Posted in SharePoint

In this post I describe how to create a custom SharePoint Event Receiver using the Visual Studio Extensions for SharePoint Services.

Software Requirements

Windows Server 2003/2008
SharePoint Services 3.0/Server 2007
Visual Studio 2005/2008
Visual Studio Extensions für SharePoint Services

Download Visual Studio Extensions

Visual Studio 2005: Download page
Visual Studio 2008: Download page
Preconfigured Virtual Machine: Download page

Description
We will develop an event receiver that prevents documents from being deleted by cancelling all delete operations.

Step 1: Set up visual studio project
Open Visual Studio and create an „Empty“ SharePoint Project.

Now add a new item to the project called Event Receiver (Project -> Add new Item -> Event Receiver)

Pick document library.

Now your project should look like this:

Weg got a strong name key to sign the assembly that will be deployed to the global assembly cache (GAC), some SharePoint references and two code files and xml files.

The ItemEventReceiver class contains all events that will be fired when something happens to list items like adding, updating or deleting of files.
The ListEventReceiver class contains all events that will be fired when something happens to the list itself like adding or removing columns

Step 2: Add event code

We want to cancel delete operations so we have to implement an event in the ItemEventReceiver class. Open it and uncomment the ItemDeleting event.

///
/// Synchronous before event that occurs before an existing item 
/// is completely deleted.
///
/// A Microsoft.SharePoint.SPItemEventProperties object that 
/// represents properties of the event handler.
public override void ItemDeleting(SPItemEventProperties properties)
{
  properties.Cancel = true;
  properties.ErrorMessage = "Deleting of Items not allowed!";
}

Build the project to check for errors, there shouldn’t be any.

Step 3: Deploy

Visual Studio can deploy the event receiver for you. Just select Build –> Deploy from the menu.

What happen’s:
Visual Studio creates one feature for each of your event receivers and uses the SharePoint console to check for errors. If there are no errors visual studio creates a deployable solution package (wsp) and a setup.bat script that can be used to deploy and undeploy the solution. Finally visual studio executes the setup.bat.

Your event receiver is now deployed and activated on the root web site, not on sub sites.
If you want to test te event receiver on a sub site you have to activate it first: Navigate to Site Settings -> Site Feature and activate the feature MyEventReceiverItemEventReceiver.
(I’ll show how to change the receiver name later in this article.)

Step 4: Test

Pick an existing document library on the site or create a new one. Upload a document and try to delete it. You should receive a message like this:

If you deactivate the feature MyEventReceiverItemEventReceiver you will be able to delete the file.

Step 5: Feature description

To give the feature a more meaningful description we can modify the feature.xml. To find this file make invisible files visible to your solution explorer:

Discover the pkg folder and open the file MyEventReceiverItemEventReceiver\feature.xml

You can modify the Title attribute and add a Description attribute:

<?xml version="1.0" encoding="utf-8"?>
<Feature 
  Id="ddeefbb1-cff7-4198-9170-f1a477168e5e" 
  Title="File keeper" 
  Description="event receiver that prevents doclib files 
    from being deleted." 
  Scope="Web" 
  Version="1.0.0.0" 
  Hidden="FALSE" 
  DefaultResourceFile="core" 
  xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest 
      Location="MyEventReceiverItemEventReceiver\ItemEventReceiver.xml" />
  </ElementManifests>
</Feature>

Now rebuild and deploy your project. In your SharePoint site navigate to Site Settings -> Site features. Here you see the new description so your SharePoint administrators can understand what’s this feature is about.

The event receiver is attached to all document libraries of the site where the feature is activated.
If you want to attach the Event Receiver to one single list you have to code this with a custom
Feature Event Receiver or use this tool:

EventReceiver-Installer for SharePoint

Have fun,
Alex

Tags: ,

Read Word Document Properties from SharePoint property bag

May 6th, 2008 | No Comments | Posted in .NET, SharePoint

Word documents have some extended properties like category, title or comments wich your can edit within word. In some cases you might want to read these document properties from code deployed within SharePoint. For example if you want to create a content type from a document and set the description of the content type to the value of the document’s comments.

The following example runs through all items of the document library “documents” on the root site and prints out document properties.

using (SPSite site = new SPSite("http://localhost"))
{
  using (SPWeb web = site.OpenWeb())
  {
    SPDocumentLibrary lib = (SPDocumentLibrary)web.Lists["Documents"];
    foreach (SPListItem item in lib.Items)
    {
      if (item.File.Properties.Contains("_Comments"))
    {
        Console.WriteLine("File {0} contains comment {1}.", 
          item.File.Name, item.File.Properties["_Comments"]);
      }
      if (item.File.Properties.Contains("_Category"))
     {
        Console.WriteLine("File {0} contains category {1}.", 
          item.File.Name, item.File.Properties["_Category"]);
      }
      if (item.File.Properties.Contains("Subject"))
      {
        Console.WriteLine("File {0} contains subject {1}.", 
          item.File.Name, item.File.Properties["Subject"]);
      }
      if (item.File.Properties.Contains("Keywords"))
     {
        Console.WriteLine("File {0} contains keywords {1}.", 
          item.File.Name, item.File.Properties["Keywords"]);
      }
    }
  }
}
Tags: , ,

Change SharePoint ContentType of ListItem

May 4th, 2008 | No Comments | Posted in .NET, SharePoint

The user interface of SharePoint allows you to select or change the ContentType of a list item. I asked myself how this could be done by code. It wasn’t as easy as I thought.

The class ListItem has a property ContentType but it’s readonly. I had to reflect the Microsoft.SharePoint.dll and finally used this workaround to change the content type:

void SetContentType (SPListItem item, SPContentType ct)
{
  item["ContentTypeId"] = ct.Id;
  item.Update();
}

In addition I wanted to set the ContentType of ListItems to their parent content type. Setting the content type to the type of the parent content type doesn’t change anything because item.ContentType.Parent and item.ContentType are equal. So I tried the parent of the parent and it worked:

void SetContentTypeToParentType (SPListItem item)
{
  item["ContentTypeId"] = item.ContentType.Parent.Parent.Id;
  item.Update();
}
Tags:

Hello world!

April 18th, 2008 | No Comments | Posted in .NET

Welcome to my development blog. This is my first post with a hello world example to check out how the syntax highlightning plugin works together with my theme.

public class Hello
{
  ///<summary>
  ///This program says Hello World!
  ///</summary>
  public static void main(String[] args)
  {
    // Write a line to the console
    Console.WriteLine("Hello World!");
  }
}

This is a wordpress blog I use the WP-Syntax plugin for syntax highlightning and the Statement theme as template for my theme and the tag cloud plugin from kl3tte.