Friday, July 10, 2009

Debug Sharepoint Event Receiver

Debugging is kind of important when developing a new application. In case of event receiver it is more important as errors are not visible unless they are logged in the text files or in the event log. For event receiver, you cannot start application with F5; you need to set the break point in the code, and wait until item is added or deleted from list.

Furthermore, event receiver DLL needs to be in GAC. It cannot be deployed in the bin folder of web application like web part DLL. It means that, for debugging, your PDB (symbols database) has to be in GAC as well. This is what everybody recommends. Since you can only add DLLs in GAC, there is no straight way how to do that. A simple trick which always works is to place PDB file in the bin folder of web application.

This is the how you can debug event receiver without adding PDB file in the GAC.

1) Right click on project properties of Event Receiver project
2) Go to Build tab
3) Change Output path: to c:\Inetpub\wwwroot\wss\VirtualDirectories\$webApplication$\bin\ where $webApplication$ is you web application folder
4) Build project in Debug mode to create the PDB file and DLL in the \bin of web application
5) If GAC has DLL build in the Release mode, uninstall it
6) Copy or install DLL (Debug mode build) file from web application's \bin folder to (GAC) c:\Windows\Assembly folder
7) Reset IIS Server
8) Hit any page on the SharePoint 2007 web application. It will load W3WP.exe.
9) Attach Debugger to W3WP.exe. If you have multiple W3WP.exe select process by user name
10) Perform add, delete or update operation on a list. Debugger will hit first break point. Make sure to replace DLL in the GAC with every code change.

Thursday, July 2, 2009

Navigation - Custom TreeView control

This SPSTreeViewNavigator, a custom asp.net TreeView control provides simple SharePoint sites navigation feature. It can be bundled either in the web part or used on the custom .aspx page to provide site relative navigational TreeView. This control exposes RootWeb property. Set it to SPWeb object of a site. It will create navigational TreeView representing site hierarchy of associated site. When assigned with RootWeb of site collection, it will create navigational TreeView for entire site collection.

TreeView is populated on demand to achieve better performance.




   1:  using System;
   2:  using System.Web.UI.WebControls;
   3:  using System.Xml;
   4:  using System.Collections;
   5:  using System.Collections.Generic;
   6:  using Microsoft.SharePoint;
   7:  using System.Text.RegularExpressions;
   8:   
   9:  namespace YourNameSpace.Controls
  10:  {
  11:      public class SPSTreeViewNavigator : TreeView
  12:      {
  13:          private SPWeb _rootWeb;
  14:          public string NODE_IMAGE_URL = "/_layouts/Images/cat.gif";
  15:   
  16:          public SPWeb RootWeb
  17:          {
  18:              get { return _rootWeb; }
  19:              set { _rootWeb = value; }
  20:          }
  21:   
  22:          protected override void OnLoad(EventArgs e)
  23:          {
  24:              base.OnLoad(e);
  25:              InitializeTreeView();
  26:          }
  27:   
  28:          //Populate TreeView on demand 
  29:          void DataViewTreeView_TreeNodePopulate(object sender, TreeNodeEventArgs e)
  30:          {
  31:              PopulateChildNodes(e.Node);
  32:          }
  33:   
  34:          void InitializeTreeView()
  35:          {
  36:              this.Height = Unit.Percentage(100);
  37:              this.Width = Unit.Percentage(100);
  38:              this.ShowCheckBoxes = TreeNodeTypes.All;
  39:              this.EnableClientScript = true;
  40:              this.ShowExpandCollapse = true;
  41:              //View State must be enable  
  42:              this.EnableViewState = true;
  43:              this.ShowLines = true;
  44:              this.TreeNodePopulate += DataViewTreeView_TreeNodePopulate;
  45:              this.NodeStyle.ImageUrl = NODE_IMAGE_URL;
  46:              if (!this.Page.IsPostBack)
  47:              {
  48:                  this.Nodes.Clear(); PopulateRootNode(this);
  49:              }
  50:          }
  51:   
  52:          void PopulateChildNodes(TreeNode node)
  53:          {
  54:              Guid webGuidId = new Guid(node.Value);
  55:              using (SPSite spSite = new SPSite(_rootWeb.Site.ID))
  56:              {

  57:                  using (SPWeb web = spSite.OpenWeb(webGuidId))
  58:                  {
  59:                      foreach (SPWeb spWeb in web.Webs)
  60:                      {
  61:                          PopulateTreeNode(spWeb, node);
  62:                      }
  63:                  }
  64:              }
  65:          }
  66:   
  67:          private void PopulateTreeNode(SPWeb web, TreeNode node)
  68:          {
  69:              TreeNode newNode = new TreeNode(web.Title, web.ID.ToString(),
  70:                                     NODE_IMAGE_URL, web.ServerRelativeUrl, string.Empty); newNode.PopulateOnDemand = true;
  71:              newNode.Expanded = false;
  72:              newNode.SelectAction = TreeNodeSelectAction.SelectExpand;
  73:              node.ChildNodes.Add(newNode);
  74:          }
  75:   
  76:          //Populate root node and next level child nodes  
  77:          void PopulateRootNode(TreeView treeView)
  78:          {

  79:              TreeNode node = new TreeNode();
  80:              SPWeb web = _rootWeb; node.Text = web.Title;
  81:              node.Value = web.ID.ToString();
  82:              node.NavigateUrl = web.ServerRelativeUrl;
  83:              node.PopulateOnDemand = true;
  84:              node.ShowCheckBox = true;
  85:              node.Expand();
  86:              treeView.Nodes.Add(node);
  87:          }
  88:      }
  89:  }
  90:   
  91:   
  92:   


Following is example of client code. Create instance of SPSTreeViewNavigator control and initialize it's RootWeb property with SPWeb object.



   1:              SPSTreeViewNavigator treeView = new SPSTreeViewNavigator();

   2:              treeView.RootWeb = SPContext.Current.Site.OpenWeb();

   3:              Controls.Add(treeView);



Following image shows SPSTreeViewNavigator in action, with TreeView fully expanded.
 

Wednesday, July 1, 2009

Auto Publish documents

SharePoint 2007 allows check-in, check out, publish and approve documents in the document libraries. This can be achieved via SharePoint object model. Here is an example in C#.

This code snippet will work for document libraries with 'Required Approval' disabled as well as enabled. If you try to approve document which does not require approval, exception will be generated.

   1:  private void publish(SPWeb web, string listName)
   2:  {
   3:      SPList list = web.Lists[listName];
   4:      web.AllowUnsafeUpdates = true;
   5:      foreach (SPListItem item in list.Items)
   6:      {
   7:          SPFile sourceFile = item.File;
   8:          try
   9:          {                    
  10:              if (sourceFile.Level == SPFileLevel.Draft  sourceFile.Level == SPFileLevel.Checkout)
  11:              {
  12:                  //Check in file 
  13:                  if (sourceFile.CheckOutStatus != SPFile.SPCheckOutStatus.None)
  14:                      sourceFile.CheckIn("System CheckIn", SPCheckinType.MajorCheckIn);
  15:   
  16:                  //Submit file for content approval 
  17:                  sourceFile.Publish("System published.");
  18:   
  19:                  //Approve file if 'Require content approval for submitted items' is enabled
  20:                  //Exception will occur trying to approve document which doesn't require approval
  21:                  if (sourceFile.Item.ModerationInformation != null)
  22:                  {
  23:                      if (sourceFile.Item.ModerationInformation.Status == SPModerationStatusType.Pending)
  24:                          sourceFile.Approve("System approved.");
  25:                  }
  26:                  sourceFile.Update();
  27:                  _publishedDocuments.Append("<br>" + web.Url + "/" + sourceFile.Url);
  28:              }
  29:          }
  30:          catch (System.Exception ex)
  31:          {
  32:               //handle exception here
  33:          }
  34:      }
  35:      web.AllowUnsafeUpdates = false;
  36:  }