Thursday, September 30, 2010

Quick way to determine processes which use dll assembly

In every day Sharepoint development we often need to update assemblies in GAC via WSPBuilder. Sometimes (especially if you use ReSharper) you will see access denied exception which is caused by the fact that assembly being updated is locked by another process:

   1: WSPBuilder AddIn Error
   2: System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
   3:    at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   4:    at System.GACManagedAccess.AssemblyCache.InstallAssembly(String assemblyPath, InstallReference reference, AssemblyCommitFlags flags)
   5:    at WSPTools.VisualStudio.VSAddIn.Library.Commands.CopyToGAC.Execute()
   6:    at WSPTools.VisualStudio.VSAddIn.VSMenuHandler.Execute(String commandName)
   7:    at WSPTools.VisualStudio.VSAddIn.Connect.Exec(String commandName, vsCommandExecOption executeOption, Object& varIn, Object& varOut, Boolean& handled)

Sometimes adding assembly 2nd time solves the problem, sometimes not. In the last case you need to determine what process blocked your assembly. In order to do it you can use GUI procexp utility (Ctrl+F to find dlls attached to process) from Sysinternals. There is also built-in Windows utility tasklist which allows you to find what processes use specified dll assembly:

   1: tasklist /m myassembly.dll
   2:  
   3: Image Name                     PID Modules
   4: ========================= ======== ============================================
   5: devenv.exe                    2332 myassembly.dll
   6: w3wp.exe                      2892 myassembly.dll

This little tip may help you not only in Sharepoint development as well.

Monday, September 27, 2010

Fix NullReferenceException after adding new controls on Sharepoint page

I would like to share a little trick which allows to fix NullReferenceException (object reference not set to an instance of an object) when you add new server control on your application _layouts page or user control in control templates folder. So you add e.g. new <asp:Textbox ID=”txtEmail” runat=”server” /> control and add appropriate protected Textbox txtEmail into codebehind class of your page. But when you try to access properties of this new control you may get NullReferenceException in runtime:

   1: // here NullReferenceException can occur
   2: this.txtEmail.Text = "foo@example.com";

This problem is rare but happens. In order to fix it you can at first try to clear "Temporary ASP.NET Files" folder. But sometimes it doesn’t help. Ofcourse you can use workaround like this:

   1: var txtEmail = (TextBox)FindControl("txtEmail");
   2: txtEmail.Text = "foo@example.com";

but it looks not effective and looks not elegant (especially if all other controls are working successfully). So if you encountered with such situation you can try to add the following line on top of you aspx page of ascx control:

   1: <%@ Register TagPrefix="asp" Namespace="System.Web.UI.WebControls" Assembly="System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" %>

and copy file into 12 hive. Sometime it helps. After that (if NullReferenceException disappeared) you can remove this line from page – it should still work after that. Thanks hodzanassredin which told about this workaround.

Friday, September 24, 2010

Create custom sites in Sharepoint using site definitions: step by step guide - part 1

If you work with Sharepoint then this theme is most probably well known for you. Any business have its own requirements and rules many of which are not fulfilled with OTB Sharepoint functionality. In this case we perform customization of OTB features for real life business needs.  With this article I would like to start a series of post where I will try to describe one of the important and widely required customizations: creation of custom sites in Sharepoint using custom site definitions. I will deep inside the process of site creation in Sharepoint mostly from developer point of view, i.e. creation and customization of sites using Sharepoint Designer are out of scope. Another purpose of this posts is to have a reference guide for forums threads I participate in.

Lets say we have a company which has many branches all over the world. We have a requirement to create a Sharepoint-based portal which will have own sub sites for each branch (for simplicity lets assume that we have single site collection per company with root site http://www.contoso.com. Branches will have the following URLs http://www.contoso.com/usa, http://www.contoso.com/europe, etc). Sites of all branches have more or less the same well known structure (i.e. its own sub sites, lists, pages, web parts) and settings (security settings, navigation, etc). Lets say they will have the following sub sites:

   1: root
   2:  |
   3:  |----USA
   4:  |    |
   5:  |    |----Sales
   6:  |    |----IT
   7:  |    |----HR
   8:  |
   9:  |----Europe
  10:  |    |
  11:  |    |----Sales
  12:  |    |----IT
  13:  |    |----HR
  14: ...

If company will open its branch in new country we need to have simple and fast process of creation of new site for this branch in company’s portal. Also we need to make this process very flexible and customizable for future business requirements changes.

As I already mentioned there are different ways to make customizations in Sharepoint. You can save site as template (.stp) and create a new site based on this template. Also you can use stsadm operations export and import and then customize new site via Sharepoint Designer. All these methods will require manual work from administrator. It is suitable solution when there are not so many sites with similar templates which should be created or if they are created rarely. But if company has thousands of branches and for each of them separate web site is needed then automation of site creation becomes crucial for business. In this case best option in my opinion is to use one of the Sharepoint extensibility points - custom site definitions. If you are not familiar with site definitions or you have confused by site template and site definition terms I recommend you to check this article first: Working with Site Templates and Definitions. Shortly site template is .stp file created using existing site. This file will not be modified once you created it. Site definition – is fully customizable definition of web site located in 12/Template/SiteTemplates folder in onet.xml files.

We will go further then most of examples about custom sites creation and consider custom site creation process, i.e. not only custom site definitions. Having custom site definition the only thing you can do – is to use OTB Create Site page (12/Templates/Layouts/newsbweb.aspx) and choose custom definition in template picker control. But what if we need specify some custom parameters which will be used during site creation? In this case we have to implement custom Create Site page as well. But lets go through the process step by step.

Lets start from creating Sharepoint artifacts for our branch sites. At first we need clearly understand what we want to create in terms of MOSS. In our case it is not simple site as it has several sub sites under it (Sales, IT, HR). Using Sharepoint terminology we need to create portal for branch which will have root site of branch and 3 mentioned sub sites. Don’t get messed with terms. From point of view of end users there is one top level portal http://www.contoso.com which have many sub sites according to each branch. But we know that each branch sub site is in turn also portal in terms of MOSS.

Ok when we know what we should create we also need to choose whether we will create site definitions of sites (members of portal) from scratch or we will use some existing Sharepoint site definition as a base with further customization. In this post we will consider 2nd variant and will use OTB Publishing Site web definition as this is very common requirement in real life scenarios – customization of publishing sites.

In order to create portal site definition we need to create webtemp file in 12/Template/{lcid}/XML folder, where {lcid} is a placeholder for those locales which you need to support. I.e. if you need to create company’s branch portal for English and Swedish languages you have to create 2 webtemp files in the following folders:

  • 12/Template/1033/XML – this is for English
  • 12/Template/1053/XML – this is for Swedish

You can read more about portal webtemp files in this article: Portal Site Template File. Lets name our file webtempContosoBranchSitePortal.xml. In our case it will have the following content:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <Templates>
   3:   <Template Name="ContosoBranchSitePortal" ID="10001">
   4:     <Configuration ID="0"
   5:       Title="Contoso Branch"
   6:       Description=""
   7:       ProvisionAssembly="Contoso.Branches, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a91ac4533350b8ae"
   8:       ProvisionClass="Contoso.Branches.BranchSitePortalProvisioningProvider"
   9:       ProvisionData="SiteTemplates\\ContosoBranchSitePortal\\ContosoBranchSitePortalWebManifest.xml"
  10:       RootWebOnly="FALSE"
  11:       Hidden="FALSE"
  12:       ImageUrl="/_layouts/images/stsprev.png"
  13:       DisplayCategory="Contoso" />
  14:   </Template>
  15: </Templates>

I will not repeat msdn and technet materials and describe all attributes here – you can find it using link I provided above. What is important for us now – is that we defined site template for portal with name “ContosoBranchSitePortal” and ID = 10001. Now if you will copy this file into 12 hive and make iisreset when you go to OTB Create Site page and specify this ID in query string (http://example.com/_layouts/newsbweb.aspx?ID=10001) you will see it in template picker control under Contoso category (DisplayCategory attribute in our webtemp file):

01

Notice about 2 attributes in webtempContosoBranchSitePortal.xml: ProvisionAssembly and ProvisionClass. Like in many other places in Sharepoint they contain assembly full name and fully qualified class name which will be used at some point of provisioning. When you use Publishing Site definition as base definition for portal you will need to use OTB PortalProvisioningProvider class from Microsoft.SharePoint.Publishing assembly. But in our case this is custom portal provisioning provider which is executed when portal is provisioned. In this example I want to show as much customization opportunities as possible so instead of OTB portal provisioning provider I used custom one. This is quite powerful technique which allows you to execute the code before or after provisioning. Unfortunately PortalProvisioningProvider class is sealed so you can’t just inherit it in your custom provider. But you can aggregate it as shown in the following code:

   1: namespace Contoso.Branches
   2: {
   3:     public class BranchSitePortalProvisioningProvider : SPWebProvisioningProvider
   4:     {
   5:         public override void Provision(SPWebProvisioningProperties props)
   6:         {
   7:             // todo: add code which will run before provisioining
   8:             var publishingPortalProvisioningProvider = new PortalProvisioningProvider();
   9:             publishingPortalProvisioningProvider.Provision(props);
  10:             // todo: add code which will run after provisioning
  11:         }
  12:     }
  13: }

As shown on example you can customize creation process by adding code which will run before (when no sub sites were created yet) and after provisioning (where all portal structure is ready). But where and how this structure is defined? The answer is in portal web manifest defined in ProvisionData attribute in webtempContosoBranchSitePortal.xml file:

ProvisionData="SiteTemplates\\ContosoBranchSitePortal\\ContosoBranchSitePortalWebManifest.xml

As you probably know 12/Template/SiteTemplates folder is the location of site definitions in onet.xml files (see this article in msdn for more details about structure of onet.xml files). In short onet.xml file is the basic element in site provisioning process in Sharepoint. It contains features, document templates, lists and other artifacts which will be provisioned into the site created based on configurations defined in this onet.xml file. But if you create a portal then instead of onet.xml file you should place portal web manifest which contains portal structure with references to another site definitions. In our case this is ContosoBranchSitePortalWebManifest.xml file in ContosoBranchSitePortal folder:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <!-- _lcid="1033" _version="12.0.4518" _dal="1" -->
   3: <!-- _LocalBinding -->
   4: <portal xmlns="PortalTemplate.xsd">
   5:   <web name="Home" siteDefinition="ContosoBranchSite#0" displayName="$Resources:ContosoBranch,Site_Home_DisplayName;" description="">
   6:     <webs>
   7:       <web name="Sales" siteDefinition="ContosoBranchSite#1" displayName="$Resources:ContosoBranch,Site_Sales_DisplayName;" description="" />
   8:       <web name="IT" siteDefinition="ContosoBranchSite#2" displayName="$Resources:ContosoBranch,Site_IT_DisplayName;" description="" />
   9:       <web name="HR" siteDefinition="ContosoBranchSite#3" displayName="$Resources:ContosoBranch,Site_HR_DisplayName;" description="" />
  10:     </webs>
  11:   </web>
  12: </portal>

As you can see we defined root site (Home) and 3 subsites (Sales, IT and HR). Name attributes will be used as URLs of sub sites (except root site of portal where URL is specified in Create Page) and displayName attribute contains localizable titles of web sites (resource file ContosoBranch.resx should be located in 12/Resources folder as well as its localized versions like ContosoBranch.en-us.resx). Most important attribute here is siteDefinition. It tells Sharepoint what site definition should be used for each site of portal. I.e. for Sales sub site MOSS will use site definition ContosoBranchSite#1.

But what does it mean and how to create site definitions I will describe in next part of the series. Also in next parts I will show how to customize Create Site page and many other interesting things.

Update 2010-10-28: 2nd part of the series is posted here.

Sunday, September 12, 2010

Fix “CSC : error CS0006: Metadata file could not be found” after update to TFS 2010

We use CI for our Sharepoint projects. Some time ago we performed upgrade to TFS 2010 from 2008 version. After migration when all functionality of source control was working we encountered with problem that our build server failed to build solutions. One of the solutions contains ~ 40 projects. During investigation of build logs I found that it contains the following errors:

CSC : error CS0006: Metadata file MyProject.dll could not be found

Such errors occurred when msbuild tried to build projects which have dependencies on MyProject.dll, i.e. not MyProject itself. According to logs MyProject was not build at all at the moment when msbuild compiled dependent projects (projects which have reference on MyProject). So my hypothesis was that problem is caused somehow by wrong build order.

After searching some time I found that other people also encountered with such problems. In some forums people complained that this error may occur also on TFS 2008 (in our case it worked well until upgrade). It was also mentioned that problem is caused by wrong build order. At the same time build order in VS was correct and projects were built successfully in it. So seems like VS and msbuild use different ways to determine build order.

During investigation of build order problem in msbuild I found useful post where author explicitly specified project dependencies in VS solution (sln file) in text editor (in case of 2008 version). So for example if you have 2 projects in solution Project1 and Project2 where Project2 depends on Project1 (Project2 has reference on Project1) then you should specify it in sln file by the following way:

   1: Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project1", "Project1.csproj", "{D3D054F9-DAD5-4745-B7EA-072F7DD784F2}"
   2: EndProject
   3: Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project2", "Project2.csproj", "{DEF8CE58-C9E9-41C9-8016-C77E54FD31D5}"
   4:         ProjectSection(ProjectDependencies) = postProject
   5:                 {D3D054F9-DAD5-4745-B7EA-072F7DD784F2} = {D3D054F9-DAD5-4745-B7EA-072F7DD784F2}
   6:         EndProjectSection
   7: EndProject

This is very creative work to specify all dependencies manually using projects guids if you have ~ 40 projects in solution :) Likely I was forced to do it only for several core projects (which almost all other projects have reference to) and for those projects which caused errors in build log. It was enough to help msbuild to untie the tangle of build dependencies. After that our build server started to work again.