Sharepoint

There really is LINQ to SharePoint

This is probably old hat, but here it is: http://www.codeplex.com/LINQtoSharePoint. Our Information Worker group had its regular meeting last evening with a special focus on development. When exploring all the ways the development experience could be improved in the next version of SharePoint (develop on a workstation! yeah!) one of the attendies asked for LINQ querying lists. Somewhere in the back of my head it rang a bell, but I couldn't put my finger on it. So here it is, follow the link above. Never underestimate the power of CodePlex...

Published: 25-03-2009 by Wim The | 0 Comments | 0 Links to this post
 

Easy SharePoint site branding with the ASP.NET ExpressionBuilder

Branding a SharePoint site is usually a case of deciding which content is common for different brands and which content is really different. If at this point you find that there really is common content and that the only difference you want to express for that content is styling and a few optical tweaks, you will find that the challenge is then to maintain that in a single place. What you don´t want is duplicating that common information across different sites, with the risk of stray site differences or a lot of extra work for every simple change. The solution that SharePoint offers is content replication, this would then require defining the different brand sites and deploy content from a central 'mother' site.

As an alternative I will propose here to consider branding by defining you own ExpressionBuilder class and using that across pages and of course in the master page. SharePoint offers its own SPUrlExpressionBuilder in the form of $SPUrl. You can find it used in the default publishing templates like this:

 

    <SharePoint:CssRegistration name="<% $SPUrl:~SiteCollection/Style Library/~language/Core Styles/Band.css%>" runat="server"/>

    <SharePoint:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/controls.css %>" runat="server"/>

    <SharePoint:CssRegistration name="<% $SPUrl:~SiteCollection/Style Library/zz1_blue.css%>" runat="server"/>

...

The SharePoint SPUrlExpressionBuilder is documented and interprets the the expression you pass it by replacing ~SiteCollection with the site collection Url and the ~language expression with the current locale for the site. The easiest solution to branding would be introducing your own ~brand expression. That would allow you to simply add your own branding css style:

<SharePoint:CssRegistration name="<% $SPUrl:~SiteCollection/Style Library/MyProduct/~brand/Brand.css%>" runat="server"/>

Or you could reference your branded images like this:

        <asp:Image ID="Logo" runat="server" CssClass="logo" ImageUrl="<%$SPUrl:~SiteCollection/Style Library/MyProduct/Images/~brand/logo.gif%>" ToolTip="Logo " ></asp:Image>

You can trace it to the Microsoft.SharePoint.Publishing dll and you can even reference the Expression builder in the Microsoft.SharePoint.Publishing.WebControls.SPUrlExpressionBuilder. If you then dive into its code with Reflector you will be disappointed by finding that it cannot be extended to interpret your expressions for branding and that it is a sealed piece of code. This leaves no other option than use containment of the .SPUrlExpressionBuilder class and extend it by introducing some extra code. Here is my version:

using System;
using System.Collections.Generic; using System.Text;
using System.Web.Compilation;
using System.Web;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.Utilities;
using System.Security.Permissions;
using System.CodeDom;
using System.ComponentModel;
using System.Web.UI;
 
/// <summary>
/// This class allows the brand to be part of a url expression. It is based on the SPUrl expression builder object and extends it with
/// with specific branding for your product.
/// </summary>
[ExpressionPrefix("MySPUrl")]
public class MySPUrlExpressionBuilder: ExpressionBuilder
{
   const string BrandPlaceholder = "~brand"; 
 
    // Contains base class, because it is a sealed class 
   private SPUrlExpressionBuilder builderBase; 
 
   /// <summary> 
   /// Replace placeholders with relevant data 
   /// </summary> 
   /// <param name="expression"></param> 
   /// <returns></returns> 
   public static object EvaluateUrlExpression(string expression) 
  
      string serverRelativeUrlFromPrefixedUrl =   SPUtility.GetServerRelativeUrlFromPrefixedUrl(expression); 
 
      for (int i = serverRelativeUrlFromPrefixedUrl.IndexOf(BrandPlaceholder, 0, StringComparison.OrdinalIgnoreCase); 
i > 0; i = serverRelativeUrlFromPrefixedUrl.IndexOf(BrandPlaceholder, 0, StringComparison.OrdinalIgnoreCase)) 
     
         StringBuilder builder = new StringBuilder(serverRelativeUrlFromPrefixedUrl.Substring(0, i)); 
         int PlaceholderLength = BrandPlaceholder.Length; 
 
         builder.Append(GetBrand()); // You need to find a way to get the brand at run time, maybe from the host headers 
         if ((i + PlaceholderLength) < serverRelativeUrlFromPrefixedUrl.Length) 
        
               builder.Append(serverRelativeUrlFromPrefixedUrl.Substring(i + PlaceholderLength)); 
           
            serverRelativeUrlFromPrefixedUrl = builder.ToString(); 
        
         return serverRelativeUrlFromPrefixedUrl; 
     
 
      /// <summary> 
      /// Default constructur 
      /// </summary> 
      public MySPUrlExpressionBuilder() 
     
         builderBase = new SPUrlExpressionBuilder(); 
     
 
      /// <summary> 
      /// Implements the abstract base method to return the string as built by SPUrl and additional replacements 
      /// </summary> 
      /// <param name="target"></param> 
      /// <param name="entry"></param> 
      /// <param name="parsedData"></param> 
      /// <param name="context"></param> 
      /// <returns></returns> 
      public override object EvaluateExpression(object target, System.Web.UI.BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) 
  
      string expression = (string)builderBase.EvaluateExpression(target, entry, parsedData, context); 
 
         if (expression != null) 
            return EvaluateUrlExpression(expression.ToString()); 
         return null; 
     
 
      /// <summary> 
      /// Implements the abstract base method to return a reference to a static evaluator method 
      /// </summary> 
      /// <param name="entry"></param> 
      /// <param name="parsedData"></param> 
      /// <param name="context"></param> 
      /// <returns></returns> 
      public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) 
  
      if (entry == null) 
         return null; 
      CodeExpression[] parameters = new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()) }; 
      CodeExpression expression = new       CodeMethodInvokeExpression(new    CodeTypeReferenceExpression(base.GetType()), "EvaluateUrlExpression", parameters); 
 
      if (entry.PropertyInfo == null) 
     
         return expression; 
     
      PropertyDescriptor descriptor = TypeDescriptor.GetProperties(entry.DeclaringType)[entry.PropertyInfo.Name]; 
      return new CodeCastExpression(descriptor.PropertyType, expression); 
  
 
   /// <summary> 
   /// Implements the abstract base method to signify that this class supports an evaluate method 
   /// </summary> 
   public override bool SupportsEvaluate 
  
      get 
     
         return true; 
     

 

If you put this in a dll and turn it into a SharePoint solution, you should be in business. Of course an expression builder needs to be declared in the expressionBuilder section of the web.config of the site, just like the other expression builders:

 

<compilation batch="false" debug="false">

<expressionBuilders>

<add expressionPrefix="MySPUrl" type="MyCompany.MyProduct.MySPUrlExpressionBuilder, MyCompany.MyProduct, …" />

</expressionBuilders>

</compilation>

After this you will finally be able to do easy branding:

<SharePoint:CssRegistration name="<% $MySPUrl:~SiteCollection/Style Library/MyProduct/~brand/Brand.css%>" runat="server"/>

And reference your branded images like this:

        <asp:Image ID="Logo" runat="server" CssClass="logo" ImageUrl="<%$MySPUrl:~SiteCollection/Style Library/MyProduct/Images/~brand/logo.gif%>" ToolTip="Logo " ></asp:Image>

Have your way with the code and have fun!


Published: 29-09-2008 by Wim The | 0 Comments | 0 Links to this post
 

Speed up SharePoint Development by using some free tools

 

At the moment I’m doing a lot of SharePoint 2007 development and what I’m doing the most is waiting waiting …. So I tried to speed up SharePoint development in the project I’m currently working on. I will explain in a few steps how to create a solution for SharePoint the fastest way. In this example I use some SharePoint tools that you can download for free.

For this example I want to create a feature that when it is activated is changes the name of the site.

Create a C# class library and called “MySharePointSolution1” (delete the class1.cs file). It should look like this 

The structure that I’m creating is used by a very handy tool called the WSPBuilder. You can download this tool at http://www.codeplex.com/wspbuilder. In the documentation for this tool you can read what sort of a structure is desired for having the WSPbuilder working. I won’t explain that here.

 

You can see that I created some folders that mirror the structure of the structure of SharePoint, this must be done to have the WSPBuilder tool working. I added also the “SiteNameChangeFeature” folder which contains a feature receiver code to change the site name (we look at that later). I also added a post build event that copies the dll to the GAC folder inside the VS project.

copy "$(TargetPath)" "$(ProjectDir)GAC"

The “solution” folder that I is created contains the actual solutions package for SharePoint, the “.wsp” file.

The “feature.xml” looks like this

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

<Feature Id="6395B135-6552-45bc-A842-58900C1E553E"

Title="Site name change feature"

Description="This feature will change the name of the site"

Version="1.0.0.0"

Scope ="Web"

Hidden="false"

xmlns="http://schemas.microsoft.com/sharepoint/"

ReceiverAssembly="MySharePointSolution1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=403f4a28f90a5cfd"

ReceiverClass="MySharePointSolution1.SiteNameChangeEventFeatureHandler">

</Feature>

The “SiteNameChangeFeatureHandler.cs” looks like this

using Microsoft.SharePoint;

namespace MySharePointSolution1

{

public class SiteNameChangeEventFeatureHandler : SPFeatureReceiver

{

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

object featureParent = properties.Feature.Parent;

SPWeb site = (SPWeb) featureParent;

site.Title = "A New Title";

site.Update();

site.Dispose();

}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

{

return;

}

public override void FeatureInstalled(SPFeatureReceiverProperties properties)

{

return;

}

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

{

return;

}

}

Try to build the project and the “MySharePointSolution1.dll” should appear in the GAC folder in your VS project.

Next step is to add the “WSPBuilder.exe”, “CabLib.dll” (comes with the WSPBuilder) to your VS project and add another post build event .

$(ProjectDir)wspbuilder.exe -Outputpath "$(ProjectDir)solution" -WSPName "MySharePointSolution1_v0.1.wsp"

Rebuild the project. If everything went ok then the “solution” folder should now contain a “manifest.xml” and a “MySharePointSolution1_v0.1.wsp” (press “show all files in the solutions explorer”).

The next step is to install the created wsp file into our SharePoint environment. We could use the “stsadm.exe” command line utility for this but I’m using another tool for that, the “SharePoint Solultion Installer”. You can download this tool and read the usage of this tool at http://blog.mondosoft.com/ontolica/archive/2007/03/14/Generic-SharePoint-2007-Solution-Installer.aspx . When you extract the SharePointSolutionInstaller_V1_0_3.zip you get a “setup.exe” and a “setup.exe.config”. Put these two files in the “solution” folder of the VS project.

The total solution should look something like this now

 

Modify the “setup.exe.config” with the correct solution id and title. Mine looks like this. (Your solution id is probably different. You can find your solution id in the generated “manifest.xml” or in a file called “solution.txt” in the root of the vs. project)

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

<configuration>

<appSettings>

<add key="BannerImage" value="Default"/>

<add key="LogoImage" value="None"/>

<add key="EULA" value=""/>

<add key="Require" value="MOSS"/>

<add key="SolutionId" value="93f0038b-94ec-40ef-b628-cda46bb4b5cc"/>

<add key="FarmFeatureId" value=""/>

<add key="SolutionFile" value="MySharePointSolution1_v0.1.wsp"/>

<add key="SolutionTitle" value="MySharePointSolution1"/>

<add key="SolutionVersion" value="1.0.0.0"/>

<add key="UpgradeDescription" value="Upgrades {SolutionTitle} on all frontend web servers in the SharePoint farm."/>

<add key="RequireDeploymentToCentralAdminWebApllication" value="true"/>

<add key="RequireDeploymentToAllContentWebApplications" value="false"/>

</appSettings>

</configuration>

Now you can run the setup.exe and install the solution in SharePoint. If everything went ok you should see your feature in the “site features” list.

 

The conclusion is that by using the “WSPBuilder” you get the advantage of not creating a “ddf” file and a “manifest.xml” . And by using the “SharePoint Solution Installer” tool you don’t have to use the stsadm.exe command line to install your solution in SharePoint.

One last thing you can do is add the following line to the post build event so that your new compiled dll is deployed directly to the “real” GAC.

"c:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if "$(TargetPath)"

I use another tool called the “application pool manager” you can download at http://www.harbar.net/archive/2007/04/06/App-Pool-Recycler-for-SharePoint-devs.aspx to not do a “iisreset” but only recycle the application pool, which makes the SharePoint development a bit faster.

The latest articles I read about SharePoint development are:

Development Tools and Techniques for Working with Code in Windows SharePoint Services 3.0 (Part 1 of 2)

http://msdn2.microsoft.com/en-us/library/bb530302.aspx

Development Tools and Techniques for Working with Code in Windows SharePoint Services 3.0 (Part 2 of 2)

http://msdn2.microsoft.com/en-us/library/bb530301.aspx


Published: 26-06-2007 by Rene Jansen | 0 Comments | 0 Links to this post
 

CSS Reference Chart for SharePoint 2007

During the last couple of days, I've been trying to customize this MOSS 2007 blog site to match the Aviva Solutions look-and-feel. Since I'm more a Windows developer, these CSS styles are causing me a pain in the ass. Fortunately, the Internet Explorer Developer Toolbar really helps to figure out what particular CSS class is effecting which part of your site. And if you then add Heather Solomon's excellent CSS Reference Chart for Sharepoint 2007, a web developer's life gets better and better.


Published: 15-02-2007 by Dennis Doomen | 0 Comments | 0 Links to this post