Use TFS to automate even better WSP builds with WSPBuilder

I’m doing some work with a client at the moment to set up a new TFS environment, and as part of that provide a way to have their new build server spit out WSP files for them. I have already gotten all of their developers (except one, he knows who he is :-P) on to WSP Builder as a standard way of generating WSP files for deployment, what I wanted to do now was to let them keep using WSP builder as their team build tool as well.

For those who have searched my blog before you will have seen that I have had some luck with this previously when I talked about How to get TFS to automate your WSP builds with WSPBuilder. There were a few little things about this that bugged me though which drove me to tidy it up a bit more this time around. Here is what the new post build script for a project looks like:

IF ("$(IsDesktopBuild)"=="") GOTO LocalBuild

:TfsBuild

MD "$(ProjectDir)bin\$(ConfigurationName)"
COPY "$(TargetDir)*.dll" "$(ProjectDir)bin\$(ConfigurationName)"
CD $(ProjectDir)
"C:\Program Files\WSPTools\WSPBuilderExtensions\WSPBuilder.exe"
MD "$(TargetDir)WSPs"
MOVE "$(ProjectDir)*.wsp" "$(TargetDir)WSPs"

GOTO Finish

:LocalBuild
"C:\Program Files\WSPTools\WSPBuilderExtensions\WSPBuilder.exe"

:Finish

If you compare it to the old script I was using there are a few important differences:

  1. The first line used to depend on you doing a local debug build to determine the difference between the local and team builds, which meant if you did a local release build you would have problems. The new script uses the “$(IsDesktopBuild)” property. This will be empty on a local build, and will return ‘false’ on the team build, so we can use that to determine the difference
  2. This will work with both a debug or a release build on the server with no trouble at all as it now uses the $(ConfigurationName) variable where it refers to those folders
  3. I removed the need to add WSPBuilder ot the PATH environment variable on the build and dev machines – this was just being lazy on my behalf because I didn’t want to put the full path into the script
  4. When we call WSPBuilder in the new script we don’t add any parameters to it. The reason for this is that we use a CD statement to change the working directory before we call WSPBuilder. The benefit of this is that if the project is using a WSPBuilder.exe.config file (See my post “Configuring WSPBuilder settings per Visual Studio project” for details on this) this will make the build server use the settings from this config file, which is in my opinion, just awesome
  5. This script does not rely on you setting “Copy to output directory” on any files in your project, it will automatically move the DLL’s into the source code directory on the TFS build server, run WSP Builder against that direcotry, and then move the compiled WSP back to the output folder.
  6. This one has less moving and no deleting of files, so will execute quicker on the build server
  7. There is no need for a pre-build action in this case
  8. The WSP files are included in a sub directory of the output, and all the DLL’s used in them are still included in the output

You can also remove the line after :LocalBuild to stop the postbuild from automatically running WSP Builder on a local build. I like having it there so I thought I would put it in here too. Also you might find you will want to customise the line that uses the COPY statement to copy DLL’s to the project directory to copy only DLL’s that start with your namespace, that way any referenced DLL’s that don’t necessarily belong in the library won’t be in there (so change “$(TargetDir)*.dll” to “$(TargetDir)MyPrefix.*.dll”).

So now the process to get WSP Builder to be used in a team build environment is this:

  1. Install WSPBuilder on the build server
  2. Add the above script to the post build action of any projects that should output a WSP file
  3. Set up a regular team build (remembering that you might need to still add the AdditionalReferencePath attribute to teh default TFSBuildproj file)

That’s it, which makes it much easier to set up than my first attempt at this. If you are using WSPBuilder and TFS then you should definately look at giving this a go.

Announcing SharePoint Saturday Sydney!

SharePoint Saturday Sydney

SharePoint Saturday Sydney

It’s now official! Keep your calendar free for the 8th of August because SharePoint Saturday is coming to Australia! For those of you who haven’t heard of SharePoint Saturday here is the description from our website:

Join SharePoint architects, developers, and other professionals that work with Microsoft Office SharePoint Server 2007 for ‘SharePoint Saturday’, on Saturday, August 8th, 2009.  SharePoint Saturday will be an educational, informative & lively day filled with sessions from respected SharePoint professionals & MVPs, covering a wide variety of SharePoint-orientated topics.  SharePoint Saturday is FREE, open to the public and is your local chance to immerse yourself in SharePoint!

So as you can see it sounds like a great way to spend a Saturday if you’re in Sydney. We will be providing lunch, snacks and drinks throughout the day all free of charge as well, and the good people at Microsoft have agreed to let us use their Sydney office as the venue.

So now that we have a date and a venue we need to fill the event with some great presentations! If you’re a presenter and want to come and present for us we would love to hear from you! The details and link to the sign up form are all on the website at http://www.sharepointsaturday.org/sydney.

If you are on Twitter and want to follow all the news and announcements from the event make sure you follow @SPSSydney and add if you are tweeting about it be sure to add #SPSSydney to yours tweets so their appear on our website as well!

Lastly I have to give my mate Ben Walters a mention here as well, he is the other half of the dynamic duo that is organising the event and I couldn’t be doing it without his help!

Canberra SharePoint User Group June 2009 – Creating a build server for SharePoint projects and Implementing an end-to-end accessibility strategy in MOSS

Here are the details for this month’s user group presentation! Hope to see you there!

This month we have two presentations. The first will be Chris Rigter presenting about his experience creating a continuous integration build server for SharePoint projects:

Chris Rigter has been involved SharePoint Development since 2007 and has experience developing in many of the toolsets used in SharePoint Development, including VSeWSS 1.1 & 1.2, WSP Builder and STSDev.
Coming from a strong ASP.Net/C# background, Chris is well versed in MSF for Agile.  In his latest project the decision was made to use VSeWSS 1.3.  This decision was made for one key reason – MSBuild Support, and therefore Continuous Integration.
Chris will demonstrate the set-up and use of a build server, and also show some of the other tools used by his team in setting up a professional SDLC based approach to SharePoint development.

The second presentation this month will be by Kurt Mueffelmann of HiSoftware, who has travelled to Australia from the United States to discuss how to implement an end-to-end accessibility strategy for MOSS:

Accessibility and overall content compliance is rapidly becoming more and more important when implementing SharePoint.  In a recent 2009 survey by IT industry analyst firm Gartner, accessibility compliance ranked as one of the top-5 questions posed by MOSS architects and consultants on how to meet WCAG 1.0 and now WCAG 2.0 (web content accessibility guideline). 
HiSoftware president & CEO Kurt Mueffelmann will address and demonstrate the end-to-end solution offerings that HiSoftware has created within the MOSS community environment.  With over 6,000 global downloads, the Accessibility Kit for SharePoint (AKS) and accessible Rich Text Editor (aRTE) have become the foundation for MOSS accessibility.  By integrating HiSoftware’s commercial offering, Compliance Sheriff for SharePoint, MOSS is now accessible from the architectural foundation, content authoring, content testing and site-auditing perspective. 

If you intend on coming, please let us know by registering for the event – how else would we know how much pizza should we get?
 
Door prize
This month we have a Microsoft Explorer Mini-Mouse with BlueTrack Technology as a door prize, thanks to our silver sponsor K2

Microsoft Explorer Mini Blue Track Mouse 
If you want to be in the draw for the door prize, make sure you register for the event using your full name. To win the door prize you have to be registered for the event, and present at the end of the meeting. Multiple entries will not be valid, so please don’t register more than once.

As always, the pizza is on us thanks to our gold sponsor UniqueWorld and we look forward to seeing everyone there!
 
The Canberra November SharePoint User Group meeting is taking place on 17/06/2009. The User Group will be held at Microsoft, Level 2, 44 Sydney Avenue, Barton.
Please note that due to security reasons at Microsoft Canberra, attendees arriving after 6pm will not be able to get into the building.

Embedding JavaScript files into your DLL’s

This isn’t strictly related to SharePoint development, as you can do this with any ASP.NET page, but basically the theory here is that you can avoid the need to deploy files (such as JavaScripts, images, CSS sheets, whatever) to your sites by embedding them within your DLL’s. The reason I have been looking at this from a SharePoint point of view is that if you have resources that you want to know will never be touched, you can go and put them in here instead of deploying them to your 12 hive. The added bonus is that you can un-clutter the 12 hive a little by having less of your custom files in there as well.

ASP.NET provides the special URL of “WebResource.axd” to provide these files. Essentially you call the page with an encoded reference to the file you want and the time it was last modified to get the file back out. You can generate the required URL for each file through code, so don’t worry too much about getting that one right on your own :-)

So for this example I’ll use a JavaScript file as the example, add it to your Visual Studio project. Select it in the Solution Explorer window, and in the properties window you should see the “Build Action” property – this tells the compiler what to do with the file, and for a JS file by default it will say none. Change this to “Embedded Resource”.

An example of the build action property

An example of the build action property

Next, open the AssemblyInfo.cs file (usually appears under the ‘properties’ folder). In here we need to add a reference to the file and tell the compiler what it’s MIME type is. This way when WebResource.axd is called it can build the response with the appropriate MIME type

[assembly: WebResource("DefaultNamespaceOfProject.FolderName.MyScript.js", "text/javascript")]

The way the string here is made up to identify your file is like this:

  • Start with the default namespace of your project (set in the properties window)
  • Add the path of any folders or sub-folders to where the file is within the project. So if you have your file in a folder called “scripts” which is inside a top level folder called “WebResources” you would have “WebResources.Scripts”)
  • Finish with the name of the file itself

Once the reference is in AssemblyInfo.cs you are now free to reference it in code where ever you need to. A common example I came across was needing to add JavaScript to the page to go with a specific web part. To inject a reference to your file into a page through code though you use something like this:

this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "DisableNameActiveX", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "DefaultNamespaceOfProject.FolderName.MyScript.js"));

The above line is broken into two parts – firstly the Page.ClientScript.GetWebResourceUrl() method. This will get the complicated encoded URL that is required to get to the file we are asking for. This is the best way to get this URL out because of the fact that the URL it gives you includes a time stamp of when the file was last modified, so if your DLL changes, so will the URL required to get to the resource. But once we have the URL to our JS file, its just a simple call to Page.ClientScript.RegisterClientScriptInclude() to tell it to add the reference to the JS file in the section of the document. In fact if you look through the HTML that SharePoint spits out you will see in a few places that it called WebResource.axd for JavaScript and images in its own code.

There is one other thing worth mentioning here before you run off and start doing this – the potential performance hit. It’s not something I have looked in to a whole lot, but I have not noticed any significant change in performance dealing files up this way, although logic does sorta tell me that serving the file up from the layouts folder on the file system is going to be quicker than dealing it up from inside of a DLL, so that is something to keep in mind when deciding to do things this way or not.

Writing a custom trace listener to log to the 12 hive log from the Enterprise Library logging block

I have recently been looking into ways to make use of the Microsoft Enterprise Library 4.1in a client’s SharePoint environment, and one of the places I directed my attention to right away was the logging block. The Enterprise Library stuff makes it easy to configure all sorts of settings in the web.config file to control how your applications can log data, but the problem I found immediately was there was no way for me to tell it to log certain to the 12 hive logs in SharePoint – the solution is simple though, a very easy to put together custom trace listener.

The documentation that comes with the library had a great example of writing a custom trace listener so I based mine off that one, and given that we know you can log to the SP log files with a single line of code, this is going to be a really simple class. Check out the code here:

[ConfigurationElementType(typeof(CustomTraceListenerData))]
    public class SharePointLogTraceListener : CustomTraceListener
    {
public override void TraceData(System.Diagnostics.TraceEventCache eventCache, string source, System.Diagnostics.TraceEventType eventType, int id, object data)
        {
if (data is LogEntry && this.Formatter != null)
            {
WriteLine(this.Formatter.Format(data as LogEntry));
            }
            else
            {
WriteLine(data.ToString());
            }
        }

        public override void Write(string message)
        {
PortalLog.LogString(message, null);
        }

public override void WriteLine(string message)
        {
PortalLog.LogString(message, null);
        }
    }

Basically the TraceData method is the key here, it is what is called when your application is told to write something to your log source. Basically what we are doing in this method is determining if we are being told to write a LogEntry (which will have a formatter to it to control the text output) or just a flat string message. The bonus of doing this is that the formatter for the LogEntry is still configurable in the web.config file, so you can still control the format of what is logged to the 12 hive there the same as your other logging sources.

Outside of that method, the only two methods I needed to override here were “Write” and “WriteLine”. This is where the actual writing of the log data goes to the 12 hive. Very straightforward stuff here.

So moving on from this, I am in the process of standardising some error handling stuff using the exception handling block, and including the logging into that so the client can control what errors and messages in their custom solutions get logged to where (similar to what MOSS lets you configure for its OOTB functions through the central administration diagnostic logging screen).

How to use the web application and site collection selector controls

If you have ever found yourself poking around the central admin site of your SharePoint farm and wondered “how can I use that web application selector in my code?” then you need to read this one, because you will find like I have that the web application and site collection selectors are very, very easy to use.

Basically the controls you need to put on your page are “WebApplicationSelector” and “SiteAdministrationSelector” for web applications and site collections respectively. Then basically for each of these controls in your code behind you just need to handle the “ContextChange” event – this event is thrown whenever the user changes the selection on each control. So if you are using the WebApplicationSelector you ContextChange event on the control will fire when the user chooses a new web application, so from there I can use WebApplicationSelector.CurrentItem to get the SPWebApplication object and then do whatever I need to do with it. Very simple and it automatically handles the nice UI with the popup window for the selectors and everything.

Configuring WSPBuilder settings per Visual Studio project

I have been a big fan of WSPBuilder for a long time, but I must admit I haven’t really been paying a whole attention to the new features as the releases have been coming out, I just kept on using the version I had because it was awesome and did what I needed it to do. I did find my way back to the codeplex site to download it again and I had a read over the newer features when I was there and found out this great little trick that lets you provide configuration options to it on a per VS project basis.

So if you have looked at where the WSPBuilder.exe lives, you will undoubtedly seen WSPBuilder.exe.config, which gave you some control over some of the options you can configure when it runs (and you can also set those options in the command line call to WSPBuilder as well). The cool thing that you can do (apparently since August 30 last year! Seriously I don’t believe I have been missing this for this long) is take a copy of WSPBuilder.exe.config and paste it into your Visual Studio Project directory, make the changes to the config file that should be set for that project, and then whenever you build your WSP file within Visual Studio it will obey the rules of that config file!

This has a few great benefits from my point of view, firstly you can force a project to not include assemblies – an example I had was two projects in a solution, each generated a WSP file but only 1 had a DLL in it, I could have set the configuration for that one to exclude assemblies to ensure that no matter what was built (eg someone in the team accidentally building the empty assembly)  the output will never have a WSP file. The second win relates to that, in that you can create the required configuration file and check it in to source control – this means that your team will always be building the WSP file with exactly the same settings and those settings are completely versioned! Very, very cool stuff in my opinion.

So now that I know this, my next step will be to make sure that this integration works when you have TFS build your WSP file for you (and lucky for me I should be setting up a new TFS environment for a client next week sometime so I can configure it there!). No doubt I will blog about that when it happens as well, so stay tuned for that.

In all seriousness though, WSPBuilder just continues to amaze me with what it does – Carsten Keutmann is a genius for bringing this project to life! As always you can get the latest version of WSPBuilder from http://wspbuilder.codeplex.com/ and you can read Carsten’s blog at http://keutmann.blogspot.com/.

Canberra SharePoint User Group May 2009 – Using SharePoint web services and installing and using Serivce Pack 2

Just announcing the user group details for this month. If you are on our mailing list you should have got the email, if not then you should join the mailing list!

This month we have two presentations. The first will be Tim Kremer of Spyk Software presenting about his experience with SharePoint webservices when developing ‘iShare’:

As SharePoint is getting more and more popular, users are increasing demanding access to SharePoint data in new ways, and on new platforms.

Tim Kremer will discuss developing rich client applications for Microsoft SharePoint, based on his experience in developing iShare – SharePoint for iPhone.

This talk will include an overview of SharePoint webservices, authentication gotchas, experiences supporting varied SharePoint deployments, and opinions on mobile development.

Whether you’re developing a Silverlight webpart or integration with other business systems, knowledge of SharePoint’s web services is becoming increasingly valuable.

Tim Kremer is the director of Spyk Software, a Sydney based Sharepoint consulting firm.

Related link: http://www.spyk.com/products/iShare/

The second presentation this month will be Ishai Sagi of Unique World, who will take us through the recently released Service Pack 2 for Microsoft Office, including how to install it, what to look out for, and some of the great new features that you get from it.

Looking forward to seeing you all there! Make sure you register for the event first as well. As usual it starts at 5.30pm at the Microsoft Office on Sydney Ave in Barton, and it is on next Wednesday (the 20th).

Issue with required fields in content type features

I came across this issue today when working through creating some content types for a new deployment. Basically the issue is to do with when you need to make a field required in a content type. Here is a rough example of what I was deploying:

<ContentType ID="0x010066A56ACAD18524448240E9D259F872AB"
               Name="My Content Type"
               Group="My Custom Content Types">
<FieldRefs>
<FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" />
<FieldRef ID="{fce16b4c-fe53-4793-aaab-b4892e736d15}" Name="EMail" Required="true" />
</FieldRefs>
</ContentType>

When this was getting deployed, the email field was always showing up as optional, despite the “required=’true’” part. I checked the schema and the required field is definitely supported, and the options that are available are “TRUE, True, true, FALSE, False, false”

Just to humour myself I changed the value from ‘true’ to ‘TRUE’, and wouldn’t you know it worked! I changed it back and forth a couple of times just to be sure it was definitely the cause it proved my point completely – if you need a field in a content type deployed through a feature to be required, you have to use uppercase letters for TRUE in the schema. Very weird because I would have expected that this is just parsed into a Boolean object somewhere, but apparently not! Definitely a trick to keep an eye on.

Extracting a WSP file from a SharePoint farm

I don’t know that this should really be something you need to do too often (because of course I know you all are checking your code in to an appropriate source control so you won’t ever loose a WSP file) but I did come across a scenario where we needed to get a WSP file back out of SharePoint. There isn’t a way to do this out of the box, but lucky for us it is seriously easy to write a few lines of code to do it.

SPSolutionCollection solutions = SPFarm.Local.Solutions;
foreach (SPSolutionsolution in solutions)
{
solution.SolutionFile.SaveAs(“{path to save}”)
}

The above code sample is pretty straight forward, it gets a list of every solution through the SPFarm.Local.Solutions object, and then parses through and saves each WSP file using the SolutionFile.SaveAs method. Obviously there probably wouldn’t be a need to save every WSP file, so you would add some checking in there to find the WSP file by its name or something to that extent, but the save method is just that one line of code.