SharePoint Developer Orientation – Part 5: Professional Development with Visual Studio

Get ready for Visual Studio development by setting up a SharePoint development environment and getting accustomed to Visual Studio’s SharePoint Tools.
Page Content

2011-07-17-SPDevOrientation-Part01-01.jpgGetting started with Visual Studio

This article is going to be somewhat of a diversion from the style of my previous posts. It is going to feel more basic, elementary, and possibly boring at times for some of you (sorry!). We need to set up a development environment and learn about Visual Studio’s SharePoint Tools, so please bear with me. I think these are important topics to cover in an “orientation” series, even though this information is available scattered about the internet.

The goal for this article is for readers to have a good feel for the environment they will be working in. I will cover setting up a development environment, working with SharePoint projects in Visual Studio, organizing and deploying your project with features and packages, and finally, I will wrap up with a little professional software engineering advice.

Setting up your development environment

So far in this blog series, we have only needed access to a SharePoint site, and a computer with SharePoint Designer and a web browser. With only those tools, power users can build rich applications.

For full-featured, professional SharePoint applications, however, we need Visual Studio. This requires SharePoint to be installed on the development machine. To set this up, please reference Technet and the community for instructions. In short, you will want:

  • A virtualization environment (Hyper-V, VMWare, etc.), although you could install on a physical Win7 64-bit machine
  • At least 8GB RAM (with at least 4GB allocated to the guest virtual machine)
  • Ideally, one or more SSDs or fast 7200+ rpm HDDs (host OS on one, VMs on another)
  • For best results, install 64-bit server software, and 32-bit client software (Office, browsers, etc.).
  • Install pre-requisites (SQL 2008 R2 Express+, PowerShell, IIS, etc.)
  • Install SharePoint 2010, Designer, and VS2010.
  • Install Visual Studio 2010 SharePoint Power Tools
  • Install CKS – Development Tools Edition (Server or Foundation)

Take a little time to research your options and plan your development environment.

Sandboxed Solutions

In Visual Studio, most SharePoint project types are the same. They are Empty SharePoint Projects with one or more SharePoint Project Items (SPIs) added by default. You will almost always use the Empty SharePoint Project type and add any necessary SPIs yourself. When you create a project, you will be prompted to enter a local SharePoint site to use for debugging, and choose between a sandboxed solution and a farm solution.

2011-11-08-SPDevOrientation-Part05-01.png

Many SharePoint experts will tell you to always select sandboxed and change it to farm later, if necessary. I agree with this advice, but I think there are a couple of things we need to fully understand. What are sandboxed solutions and why bother with them? They are SharePoint solutions (WSP files) that are installed into a site collection’s Solutions gallery. Anatomically, there is no difference between a sandboxed WSP file and a farm WSP file. If your solution meets certain restrictions, then it is eligible to be installed into a site collection’s Solutions gallery. The real value is that they are installable by a site collection administrator (a.k.a. “USER”) rather than a farm administrator (a.k.a. “IT”). That is why they are sometimes referred to as “user solutions” and are run by the “user code service.”

When you attempt to activate your solution from the Solutions gallery, it will be validated against sandboxed restrictions. Sandboxed solutions only have access to a limited subset of the Microsoft.SharePoint namespace, are limited to the Site Collection scope, run under the current user’s security context at all times, and cannot touch the file system. Furthermore, they run in their own process and app domain with strict CAS policies (the sandbox), and SharePoint reserves the right to shut them down if they exceed configured thresholds (CPU utilization, etc.). Farm Administrators can add more restrictions via custom solution validators, increase or decrease a solution’s thresholds, or turn off Sandboxed solutions altogether.

See Technet’s Sandboxed Solutions Overview and MSDN’s Restrictions on Sandboxed Solutions article for more information. As usual, there is guidance from the community as well.

A couple more quick notes about Sandboxed solutions… First, you can use the Packaging Explorer (View > Other Windows > Packaging Explorer) to validate your package and find out if you are still within the constraints of a Sandboxed Solution:

2011-11-08-SPDevOrientation-Part05-02.png

Finally, you can change the Sandboxed/Farm status in the project’s properties window:

2011-11-08-SPDevOrientation-Part05-03.png

SharePoint Project Items (SPIs)

To add functionality to your project, you will add SharePoint Project Items (Right-click your project > Add > New Item…).

2011-11-08-SPDevOrientation-Part05-04.png

SPIs behave like folders that contain files that are functionally related. This does not represent how the files are deployed to SharePoint. The SPI abstracts deployment details to make your life easier. Some files may end up on the file system, in the content database, or not deployed at all. Every SPI has an Elements.xml element manifest file, and a hidden SharePointProjectItem.spdata file that helps Visual Studio keep track of the SPI’s files, compiled code (SafeControl entries), and how to package it all for deployment.

Let’s look at a few examples:

2011-11-08-SPDevOrientation-Part05-05.png

  • The Empty Element SPI is the basis of all the others and literally contains an empty Elements manifest.
  • The Module SPI simply places files into the SharePoint content database (in document libraries or galleries) or the file system. It adds a <Module…> xml element to the Elements.xml manifest with one or more <File…> elements that define where to place each file.
  • The Web Part SPI is essentially a pre-configured Module SPI that places the .webpart definition into the site collection’s Web Part Gallery. In addition, it has the .cs code file for the WebPart class that is compiled. This file is not deployed (in the properties window you will see a Deployment Type of “NoDeployment”), but its namespace is tracked in a SafeControl entry so that when the solution is deployed, the code is allowed to run in the SharePoint environment. You can see this in the SharePointProjectItem.spdata file.
  • The Visual Web Part SPI goes even further by defining a user control (the .ascx is placed on the SharePoint file system in the control templates folder via a module). The user control is loaded programmatically within the WebPart class (VisualWebPart1.cs file). This allows you to visually design your web part as you would a regular ASP.NET user control.

There are many other SPIs, but there is not always a pre-defined SPI for everything you might need to build. For example, there is no Custom Action SPI out of the box. You have to add an Empty Element SPI and add the necessary XML by hand. (The CKS:DEV VS Extension adds a Custom Action SPI, by the way, among others.)

Features

Features are the logical units of functionality that users can turn on and off for a particular deployment scope (site collection, site, farm, or web application). Going to Site Settings or Central Administration, a user can see the list of features they can activate or deactivate:

2011-11-08-SPDevOrientation-Part05-06.png

Visual Studio adds Features to your project for you as SPIs are added. Generally, you will have one feature for each deployment scope you need to use, but you can have as many as you want. Not all SPIs can be deployed to all scopes, though. Web parts, for example, must be deployed at the Site Collection level (because that is where the Web Parts gallery is). You will get an error during packaging if any SPIs are in the wrong features, although the feature designer does a lot to help prevent that. It is helpful to name your features with their scopes (e.g. “Web Feature”) in Solution Explorer, but definitely provide user-friendly titles and descriptions in the feature definition itself.

Feature Receivers (right-click the feature > Add Event Receiver) allow you to run code upon FeatureActivated (post-event), FeatureDeactivating (pre-event), FeatureInstalled (post-event), FeatureUninstalling (pre-event), and FeatureUpgrading (pre-event). This enables some interesting scenarios. You can programmatically create lists and other items instead of doing so declaratively in SPIs. Or get creative with an empty feature that fires off any server code you wish upon activation and/or deactivation. Another good use of feature receivers is to clean up after yourself. Not everything is cleaned up automatically when your feature is deactivated or uninstalled. Any list instances, modules (files, including web parts), or documents you deployed will be left behind. As a best practice, you should understand the disposition of all your solution’s items and plan on how you will clean up after them, if at all. See Stefan’s blog post for an example of cleaning up after yourself.

Features can have activation dependencies on other features. Users will not be able to activate your feature until the other one is activated. It is possible to automatically and silently activate a feature yours depends on, but only if it is hidden and at the same deployment scope as your feature.

Once your feature is developed and deployed, you will have a new set of challenges upgrading features. When you are ready for version 2.0 of your solution, you will have to track your changes from the baseline manually, and explicitly lay out the upgrade steps from prior versions. If you are developing a solution that needs to be maintained and upgraded over time (as opposed to installed fresh each time or one-off site-specific solutions), you have to begin version 2.0 carefully and be disciplined as you change your solution. Always remember, if your upgrade process is getting out of hand, you can write code for the FeatureUpgrading event receiver to get over a hump. Chris O’Brien has covered feature upgrading in depth in his blog, so I will refer you to him for more details.

Packages and Deployment

A package shows which features and files will be contained in the WSP file. It is concerned only with deployment… how to package up features, mapped files (files copied directly to the file system during deployment via a mapped folder rather than provisioned in a feature via a module), and assemblies into the WSP file. When you package your project from the Build menu, your output directory will contain a WSP file you can manually deploy. Solutions are manually deployed using PowerShell for farm solutions, or the web UI for sandboxed solutions.

Visual Studio does support F5 deployment, which is handy for local deployments during development, but not deployments to other environments. F5 deployment will retract your solution if already deployed, and automatically resolve conflicts. For example, if your solution creates a list, F5 deployment will remove the list and deploy it fresh. This is not the behavior you will get when deploying in a real-world scenario, so leave yourself time to test deployments!

Professional Software Engineering

As this is an orientation series, I will only briefly mention that professional software engineering practices are possible with SharePoint. You can set up a build server for continuous integration, write unit tests with mocking frameworks, secure and version your source code with TFS, etc. You know how to do this, because you’ve done it before. Developing for SharePoint does not excuse you of your responsibilities as a professional developer to create reliable solutions. There may be pressure on you to cut corners when your power user counterparts are churning out solutions a dozen at a time. You are here to play a different role and provide value in a different way. Try not to get caught up – or let your customers or bosses get caught up – in the mistaken notion that SharePoint can solve all problems fast and cheap. You get what you pay for.

Finally, let me point you to a great resource for developers. The patterns and practices crew at Microsoft put out guidance for Developing Applications for SharePoint 2010. It is currently on MSDN, but was started and developed and refined into its current state on codeplex, where you can still find some hands on labs.

Conclusion

So where do we go from here?! This almost wraps up this orientation series. Part 6 will round it off with an example of how to build a business application. It will showcase one approach that ties in all (ok, hopefully most) of the lessons of this series

Advertisements

Inconvenient Content Query Web Part slots and CQWP’s extensibility

SharePoint 2010 Content Query Web Parts ships with the Slots capability which simplifies working with custom Item Styles. Unfortunately it turns out that Slots may be broken when working with extended CQWPs.
Page Content

 

2011-09-28-InconvenientCQWPslots-01.jpg

SharePoint 2010 Content Query Web Parts ships with the Slots capability which simplifies working with custom Item Styles. Unfortunately it turns out that Slots may be broken when working with extended CQWPs. So what is the problem exactly and, more important, how can you solve it?

Slots – and it’s not about Vegas

Slots are one of the great improvements of the Content Query Web Part in SharePoint 2010. Using slots you can decouple your custom Item Styles (presentation layer) from the underlying data. What’s even more important is that when using slots you don’t need to know the internal names of fields and map them in the hidden properties of the Content Query Web Part. Slots allow you to use the display names which gives you a really convenient way of working with custom Item Styles.

Extending Content Query Web Part with custom functionality

The standard functionality of the Content Query Web Part provided with SharePoint 2010 should be sufficient for most scenarios. However, once in a while you might come across some requirement that cannot be achieved using the standard functionality. And while you could create a whole new Web Part, it might be easier to just extend the CQWP with the missing functionality.

One scenario for extending the Content Query Web Part capabilities is to provide additional functionality that can be used in XSLT. To do that all you have to do is to inherit from the ContentByQueryWebPart class and override the ModifyXsltArgumentList method. In there you can start extending the standard functionality with custom parameters and XSLT functions.

Unfortunately, it turns out, that extending the Content Query Web Part with new XSLT capabilities comes with a price.

CQWP slots vs. custom XSLT extensions

Imagine the following Item Style template:

01 <xsl:template name="MyTemplate" match="Row[@Style='MyTemplate']" mode="itemstyle"
02   <xsl:variable name="isMember" select="contains(@Members, mv:GetUserLoginName())"/> 
03     <li> 
04         <xsl:choose> 
05             <xsl:when test="$isMember"
06                 <a href="{@SiteUrl}"><xsl:value-of select="@SiteTitle"/></a> 
07             </xsl:when> 
08             <xsl:otherwise> 
09                 <xsl:value-of select="@SiteTitle"/> 
10             </xsl:otherwise> 
11         </xsl:choose> 
12     </li> 
13 </xsl:template>

As you can see there are two slots defined (Members and SiteTitle). In between, a custom XSLT function called GetUserLoginName is called. When you open CQWP’s properties however you will see only one slot:

2011-09-28-InconvenientCQWPslots-02.jpg

Congratulations: you just broke CQWP slots.

The reason why CQWP slots and custom XSLT extensions don’t get along well is how the Content Query Web Parts generates a list of all available slots in the linked Item Style XSL file.

While building the list of all available slots, the Content Query Web Parts creates a new instance of the CQWP, binds dummy data to it and performs an XSL transformation. As you can imagine, as soon as the transformation will stumble upon your extension it will throw an exception and CQWP will stop retrieving slots for your template.

2011-09-28-InconvenientCQWPslots-03.jpg

Depending on where in your Item Style template you make a call to your custom functions, you will either see all of your slots just as if everything worked correctly, you might see only some of them (those located before the call to the custom function) or none of them.

So much for flexibility…

CQWP slots and custom XSLT extensions: better together

It turns our that it is possible to combine custom XSLT extensions with slots after all and all you need for it is a little trick. The basic idea is to make the CQWP parse all of your slots before the first call to any of your custom extensions where the exception occurs.

What doesn’t work

The most obvious solution to this issue, that you might think of, might be to define a variable for every slot, like:

1 <xsl:variable name="MySlot" select="@MySlot"/>

Unfortunately it doesn’t work. Because available slots are retrieved using an XSL transformation rather than string matching, the value of the variable is not instantiated until it’s being referred to for the first time. And if the call to your custom extension occurs before the first call to the variable, your slots will still not be picked up by the CQWP.

What does work

What you really need, to work around this issue, is a void template. A template that retrieves values of all slots and yet doesn’t output any of them.

1 <xsl:template name="void"
2     <xsl:param name="input"/> 
3     <xsl:value-of select="''"/> 
4 </xsl:template>

With that all you have to do is to modify your Item Style template so that it initializes all slots before doing anything else:

01 <xsl:template name="MyTemplate" match="Row[@Style='MyTemplate']" mode="itemstyle"
02     <xsl:call-template name="void"
03         <xsl:with-param name="input"
04             <xsl:value-of select="@Slot1"/> 
05             <xsl:value-of select="@Slot2"/> 
06             <!-- other slots -->
07         </xsl:with-param> 
08     </xsl:call-template> 
09   
10     <!-- the rest of the template -->
11 </xsl:template>

With this in place you can benefit of all your custom extensions and yet keep the CQWP fully functional.

2011-09-28-InconvenientCQWPslots-04.jpg

Bonus

Trying to find out if the Content Query Web Part will load all slots might be a tedious process especially if you’re working with Content Approval. To help you be productive I created a command line tool that allows you to check which slots will the CQWP pick up for your Item Style template.

It’s usage is simple and if you want to know everything about it just type MaventionWhatsMySlots and hit enter and all available commands will be shown to you.

2011-09-28-InconvenientCQWPslots-05.jpg

The great thing about using this tool is that all you have to do is to save your changes in the XSLT files and run the tool. No longer do you have to worry about publishing them, clearing the cache and reloading the page.

2011-09-28-InconvenientCQWPslots-06.jpg