Microsoft has great virtual labs available, but it takes some time to get in there. If you just want the lab notes, type the following in Google: site:download.microsoftvirtuallabs.com filetype:pdf or just follow this link.
SharePoint has a great way for deploying content and functionality using Windows SharePoint Services Solution Packages (WSP's). While developing a powerful new feature for SharePoint Publishing sites I had to deploy a HttpModule "the SharePoint" way. Building a HttpModule , a corresponding feature and the resulting WSP package is easy with our Macaw Solutions Factory. The actual logic in the Http Module and the feature is the difficult part. One of the things I had to do was to create a feature that registers a HTTPModule on feature activation, and removes it from the web.config on the feature deactivation. You can do this using the SPWebConfigModification class.
A good article on this topic is http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32. It contains links to other posts as well.
The Microsoft documentation can be found at SPWebConfigModification Class (Microsoft.SharePoint.Administration), I wished I scrolled down before, because a lot of valuable information can be found in the Community Content of this page (keep scrolling!).
Anyway, it took quite some time to get my HttpModule to register/unregister correctly on activation/deactivation of my web application level feature. I post the code below so you have a head-start if you have to do something similar yourself.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
// namespace must be in the form <Company>.<Product>.<FunctionalArea>.SharePoint.Features.<FeatureName>.FeatureReceiver
namespace Macaw.WcmRia.Moss2007.DualLayout.SharePoint.Features.DualLayoutSupport.FeatureReceiver
{
/// <summary>
/// Add HttpModule registration to web.config of the web application
/// </summary>
class DualLayoutSupportFeatureReceiver : SPFeatureReceiver
{
private const string WebConfigModificationOwner = "Macaw.WcmRia.Moss2007.DualLayout";
private static readonly SPWebConfigModification[] Modifications = {
// For not so obvious reasons web.config modifications inside collections
// are added based on the value of the key attribute in alphabetic order.
// Because we need to add the DualLayout module after the
// PublishingHttpModule, we prefix the name with 'Q-'.
new SPWebConfigModification()
{
// The owner of the web.config modification, useful for removing a
// group of modifications
Owner = WebConfigModificationOwner,
// Make sure that the name is a unique XPath selector for the element
// we are adding. This name is used for removing the element
Name = "add[@name='Q-Macaw.WcmRia.Moss2007.DualLayout']",
// We are going to add a new XML node to web.config
Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
// The XPath to the location of the parent node in web.config
Path = "configuration/system.web/httpModules",
// Sequence is important if there are multiple equal nodes that
// can't be identified with an XPath expression
Sequence = 0,
// The XML to insert as child node, make sure that used names match the Name selector
Value = "<add name='Q-Macaw.WcmRia.Moss2007.DualLayout' type='Macaw.WcmRia.Moss2007.DualLayout.Business.Components.HttpModule, Macaw.WcmRia.Moss2007.DualLayout.Business.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=077f92bbf864a536' />"
}
};
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
if (webApp != null)
{
AddWebConfigModifications(webApp, Modifications);
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
if (webApp != null)
{
RemoveWebConfigModificationsByOwner(webApp, WebConfigModificationOwner);
}
}
/// <summary>
/// Add a collection of web modifications to the web application
/// </summary>
/// <param name="webApp">The web application to add the modifications to</param>
/// <param name="modifications">The collection of modifications</param>
private void AddWebConfigModifications(SPWebApplication webApp, IEnumerable<SPWebConfigModification> modifications)
{
foreach (SPWebConfigModification modification in modifications)
{
webApp.WebConfigModifications.Add(modification);
}
// Commit modification additions to the specified web application
webApp.Update();
// Push modifications through the farm
webApp.WebService.ApplyWebConfigModifications();
}
/// <summary>
/// Remove modifications from the web application
/// </summary>
/// <param name="webApp">The web application to remove the modifications from</param>
/// <param name="owner"Remove all modifications that belong to the owner></param>
private void RemoveWebConfigModificationsByOwner(SPWebApplication webApp, string owner)
{
Collection<SPWebConfigModification> modificationCollection = webApp.WebConfigModifications;
Collection<SPWebConfigModification> removeCollection = new Collection<SPWebConfigModification>();
int count = modificationCollection.Count;
for (int i = 0; i < count; i++)
{
SPWebConfigModification modification = modificationCollection[i];
if (modification.Owner == owner)
{
// collect modifications to delete
removeCollection.Add(modification);
}
}
// now delete the modifications from the web application
if (removeCollection.Count > 0)
{
foreach (SPWebConfigModification modificationItem in removeCollection)
{
webApp.WebConfigModifications.Remove(modificationItem);
}
// Commit modification removals to the specified web application
webApp.Update();
// Push modifications through the farm
webApp.WebService.ApplyWebConfigModifications();
}
}
}
}
SharePoint WCM does a lot of caching. One of the things that is cached are the publishing pages. These pages are cached in the object cache. Sometimes there is a situation where you want to flush a publishing page from the cache. In my case I had to flush a publishing page from the cache in a http module. The cache id for this page is the server relative url without any characters after the url. For example: /Pages/MyFirstLittleWCMPage.aspx. Therefore the path must be "normalized" so additional "stuff" is removed. The NormalizeUrl() function does this job.
What I want to do to flush the page from the cache was:
CacheManager contextCacheManager = CacheManager.GetManager(SPContext.Current.Site);
contextCacheManager.ObjectFactory.FlushItem(NormalizeUrl(HttpContext.Current.Request.Path);
Sadly enough many interesting and powerful API classes are internal, and you need some reflection to be able to call them. Below the code I needed to write to accomplish the above. I can tell you it was a hell of a job to get to this code. That is why I share it, to give you some insight in the required magic called reflection.
Interesting components:
- I know that the assembly containing the required class is already loaded. I can do GetAssembly(typeof(PublishingPage)) to get the assembly. Will work on any class in the assembly.
- To invoke a member of a class you need the type of the class. Assembly.GetType("full.name.of.type") returns the type, also on internal classes.
- Given the type you can invoke members, where members can be static functions, properties or methods. You specify what to search for the member using BindingFlags. For example for a static public method specify BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod.
- Arguments to methods must be passed in an object array.
I hope the code below will give some insight in how to make the impossible possible.
/// <summary>
/// Flush the current publishing page from the object cache
/// </summary>
/// <remarks>
/// Reflection is used to get access to internal classes of the SharePoint framework
/// </remarks>
private void FlushCurrentPublishingPageFromCache()
{
// We need to get access to the Microsoft.SharePoint.Publishing.dll assembly, PublisingPage is in there for sure
Assembly microsoftSharePointPublishingAssembly = Assembly.GetAssembly(typeof(PublishingPage));
Type cacheManagerType = microsoftSharePointPublishingAssembly.GetType("Microsoft.SharePoint.Publishing.CacheManager", true);
object contextCacheManager = cacheManagerType.InvokeMember("GetManager",
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod,
null, null, new object[] { SPContext.Current.Site });
string cacheId = NormalizeUrl(HttpContext.Current.Request.Path);
if (contextCacheManager != null)
{
object cachedObjectFactory = contextCacheManager.GetType().InvokeMember("ObjectFactory",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty,
null, contextCacheManager, new object[] {});
cachedObjectFactory.GetType().InvokeMember("FlushItem", BindingFlags.Instance |
BindingFlags.Public | BindingFlags.InvokeMethod,
null, cachedObjectFactory, new object[] { cacheId });
}
else
{
Microsoft.Office.Server.Diagnostics.PortalLog.LogString("Unexpected error: DualLayout " +
"FlushCurrentPublishingPageFromCache: No CacheManager for page {0}", cacheId);
}
}
/// <summary>
/// Normalize url for cachId usage
/// </summary>
/// <remarks>
/// This code is copied from:
/// private static string NormalizeUrl(string url);
/// Declaring Type: Microsoft.SharePoint.Publishing.CachedObjectFactory
/// Assembly: Microsoft.SharePoint.Publishing, Version=12.0.0.0
/// </remarks>
/// <param name="url">Url to normalize</param>
/// <returns>The normalized url</returns>
private static string NormalizeUrl(string url)
{
url = SPHttpUtility.UrlPathDecode(url, false);
if (!string.IsNullOrEmpty(url))
{
int length = url.IndexOf('?');
if (length >= 0)
{
url = url.Substring(0, length);
}
}
else
{
return "";
}
int index = url.IndexOf('#');
if (index >= 0)
{
url = url.Substring(0, index);
}
return url;
}
I'm currently running around in the Visual Studio debugger to debug some complex SharePoint code. There are two things really annoy me: all the mouse-clicks needed to attach to the Internet Information Server process and the time-out you get when you are exploring complex data-structures for too long.
First my favorite key-sequence for the last week: <ALT-D>PW3<ENTER><ENTER>. I will explain it:
<Alt-D> brings up the debugging menu in Visual Studio:
With P the action "Attach to Process..." is executed, which brings you to the following window:
The list of available processes is already active. We nog need to select the Internet Information Server worker process. Each application pool has it's own worker process. These worker processes are named: w3wp.exe.
By typing W3 the first (and often only) w3wp.exe process is selected:
If there are multiple w3wp.exe processes you could select them all (SHIFT+ARROWDOWN). Now press the first time <ENTER>, which selects the w3wp.exe process(es). This results in the following window:
The "Attach" button is selected by default. This brings us to the latest <ENTER> to accept the default selection.
We are now attached to the correct Internet Information Server working process(es) and can start debugging.
Just try it a few times: <ALT-D>PW3<ENTER><ENTER>, it will become second nature in no time. Happy debugging....
... until you get the following popup window:
You have got a "ping" timeout. If you read the box well, it tells you exactly what happened, and it tells you to press the "Help" button for further details.
Most people don't read the box, and start over again. But it worth the effort to follow the described steps from the Microsoft documentation, they are a bit hard to follow:
To continue to debug, you must configure IIS to allow the worker process to continue.
To enable Terminal Services (?? Terminal Services ??)
-
Open the Administrative Tools window.
-
Click Start, and then choose Control Panel.
-
In Control Panel, choose Switch to Classic View, if necessary, and then double-click Administrative Tools.
-
In the Administrative Tools window, double-click Internet Information Services (IIS) Manager.
-
In the Internet Information Services (IIS) Manager window, expand the <computer name> node.
-
Under the <computer name> node, right-click Application Pools.
-
In the Application Pools list, right-click the name of the pool your application runs in, and then click Advanced Settings.
-
In the Advanced Settings dialog box, locate the Process Model section and choose one of the following actions:
-
Set Ping Enabled to False.
-or-
-
Set Ping Maximum Response Time to a value greater than 90 seconds.
Setting Ping Enabled to False stops IIS from checking whether the worker process is still running and keeps the worker process alive until you stop your debugged process. Setting Ping Maximum Response Time to a large value allows IIS to continue monitoring the worker process.
-
Click OK.
-
Under Services and Applications, click Services. -- Don't know what the rest of the steps if for... you are done!
A list of services appears in the right-side pane.
-
In the Services list, right-click Terminal Services, and then click Properties.
-
In the Terminal Services Properties window, locate the General tab and set Startup type to Manual.
-
Click OK to close the Advanced Settings dialog box.
-
Close the Internet Information Services (IIS) Manager window and the Administrative Tools window.
I'm running on Windows Server 2008, and below are the steps that I follow:
Just type iis in the Start Search box, this shows me two applications:
I take the top one (I'm not running under IIS 6) and get the following screen:
Right-click your application pool, advanced settings... and you get the following screen:
Set "Ping Enabled" to False, press OK, and you can drill through your data-structures in the debugger for as long as you want!
Again: "Happy debugging!"
After a weekend of hard work I have a new version of SPDevExplorer ready with many new enhancements. Download at http://spdevexplorer.codeplex.com/WorkItem/View.aspx?WorkItemId=7799
See http://weblogs.asp.net/soever/archive/tags/SPDevExplorer/default.aspx for all myposts on SPDevExplorer.
Some screen shots to give an impression:
Connect to a SharePoint site:
Checkout and edit a page from SharePoint:

Actions on the context menu of a site:
Actions on the context menu of a folder:
Actions on the context menu of a file:
Add files from working folder to SharePoint:
Version 2.2:
- Added consistent keyboard shortcuts for all context menu entries
- Changed "Published by VS 2005" and Checked in by VS 2005" to "Published by SPDevExplorer" and Checked in by SPDevExplorer"
because add-in works with both VS 2005 and VS 2008.
- All file content communication between working folder and sharepoint is now binary. Was text before, with
conversion to UTF8. This allows for uploading modified binary files and editing in Visual Studio
of non-text files.
- Extended file information on files retrieved from SharePoint with last time modified for improving
test on overwrite of modified files.
- Added "Save" to file menu. If a file is opened in Visual Studio, it is saved and the contents is saved
to SharePoint. If it is not opened in Visual Studio, if it is saved from another application to
the working folder, the file is saved to SharePoint. Now images and other files can be opened from
the working folder and saved back to SharePoint.
- Refactoring and documentation of code (first steps)
- Added "Add file..." option on folder that allows you to add files that are in the working folder, but
are not in SharePoint. This makes it possible to create files with any application in the working folder
and add them to SharePoint using Visual Studio.
- Added "Explorer working folder..." to all folders, not only to site. Makes it easier to add new files.
- Changed menu action on site "SharePoint->Settings" to "SharePoint->Site Settings
- Added "SharePoint->Open site in browser", "SharePoint->Open folder in browser", "SharePoint->Open file in browser"
to open the site, folder or file in a browser window within Visual Studio
- Added "SharePoint->Web part page maintenance" on files, this opens the file url with ?contents=1 appended in a
browser window in Visual Studio. A special page is displayed where web parts can be deleted. Useful for pages that
don't work anymore due to a not working web part
- Added method "CurrentWebServiceVersion" to the SPDevExplorer web service so we can make sure that the client side tool
and the server side web service stay in sync
Version 2.1:
- Fixed a bug where subnodes where not rendered when enabling/disabling "Show all folders and files"
- When loading a site, the site node now directly expands
- Refresh on site gave "Not implemented", it now works
- Removed SharePoint Settings and SharePoint COntents options on folders. Gave a "Not implemented"
message, and I don't see a use for them
- Add New/File, New/Folder, Get/Files, Get/Files recursive also to the Site node, to be able to do this
on the root of the site as well
- Changed Checkin to Check In, and Checkout to Check Out to be consistent with SharePoint Designer
- Disable Publish if publishing not enabled on library
- Show Publish only if file is Checked In
- If Checked Out, show Check In with the user that has file currently checked out
- Added Rename on files and folders to folder and file context menu
- Added consistent short cuts for all context menu entries
- WSP install.bat script: added -force on deploysolution so it can be executed if solution already installed
- Removed Site & System, folder with log files and contente types. Do content types through WebUI, use other tool for log files
- Fixed "Check Out" visualization of files in root of site
Version 2.0:
- Converted the project into a Visual Studio 2008 project
- Changed spelling error Domin into Domain
- Generated a strong key for the SPDevExplorer.Solution project. I got an error when installing the WSP rthat assembly was not strong-signed.
- Cookies were retrieved on an empty cookies object, this lead to a object not found exception
- Several changes to make sure that https is supported by changing the UI that full path is shown in tree.
You now see https://mysite instead of just mysite.
- Added "Explore working folder..." on site, so the cache on the local file system can be found. Want to turn
this into a feature to add files to the cache folders and be able to add these additional files.
- Added "Show info..." on files and folders, shows the cached xml info on the folder/file
- On delete file/folder, ask for confirmation
- On delete file/folder, refresh parent view to make sure it is correct again, make next node current, if not exist previous node
- Made keyboard interaction working, KeyPress was used, didn't work, now using KeyUp
- Del on keyboard now works correctly for deleting files/directories
- F5 on keyboard added for refresh. Parent folder is refreshed if on File, current folder is refreshed if on folder
- Removed (Beta) from name in window title
- Moved "SharePoint Explorer" from "View" menu to "Tools" menu, more appropriate place
- Option on site "Show all folders and files". Normally there is a list of hidden folders, but this also hides files you migh
want to edit like files in the forms folders of lists
- Removed adding list of webs to a site, gave an error and sites were never added. All sites must be added explicitly
using "connect...". I think it is also better this way.
Note that the download version is named version 2.3, but internally this is version 2.2. I messed up with the numbering.
I did a lot of additional bugfixing and enhancements on SPDevExplorer. Resulted in version 2.1 of SPDevExplorer. Download bin + sources at http://spdevexplorer.codeplex.com/WorkItem/View.aspx?WorkItemId=7799. Let me know if you find any issues.
See http://weblogs.asp.net/soever/archive/tags/SPDevExplorer/default.aspx for all myposts on SPDevExplorer.
Modifications by Serge van den Oever [Macaw]:
============================================
Version 2.1:
- Fixed a bug where subnodes were not rendered when enabling/disabling "Show all folders and files"
- When loading a site, the site node now directly expands
- Refresh on site gave "Not implemented", it now works
- Removed SharePoint Settings and SharePoint COntents options on folders. Gave a "Not implemented"
message, and I don't see a use for them
- Add New/File, New/Folder, Get/Files, Get/Files recursive also to the Site node, to be able to do this
on the root of the site as well
- Changed Checkin to Check In, and Checkout to Check Out to be consistent with SharePoint Designer
- Disable Publish if publishing not enabled on library
- Show Publish only if file is Checked In
- If Checked Out, show Check In with the user that has file currently checked out
- Added Rename on files and folders to folder and file context menu
- Added consistent short cuts for all context menu entries
- WSP install.bat script: added -force on deploysolution so it can be executed if solution already installed
- Removed Site & System, folder with log files and contente types. Do content types through WebUI, use other tool for log files
- Fixed "Check Out" visualization of files in root of site
Version 2.0:
- Converted the project into a Visual Studio 2008 project
- Changed spelling error Domin into Domain
- Generated a strong key for the SPDevExplorer.Solution project. I got an error when installing the WSP rthat assembly was not strong-signed.
- Cookies were retrieved on an empty cookies object, this lead to a object not found exception
- Several changes to make sure that https is supported by changing the UI that full path is shown in tree.
You now see https://mysite instead of just mysite.
- Added "Explore working folder..." on site, so the cache on the local file system can be found. Want to turn
this into a feature to add files to the cache folders and be able to add these additional files.
- Added "Show info..." on files and folders, shows the cached xml info on the folder/file
- On delete file/folder, ask for confirmation
- On delete file/folder, refresh parent view to make sure it is correct again, make next node current, if not exist previous node
- Made keyboard interaction working, KeyPress was used, didn't work, now using KeyUp
- Del on keyboard now works correctly for deleting files/directories
- F5 on keyboard added for refresh. Parent folder is refreshed if on File, current folder is refreshed if on folder
- Removed (Beta) from name in window title
- Moved "SharePoint Explorer" from "View" menu to "Tools" menu, more appropriate place
- Option on site "Show all folders and files". Normally there is a list of hidden folders, but this also hides files you migh
want to edit like files in the forms folders of lists
- Removed adding list of webs to a site, gave an error and sites were never added. All sites must be added explicitly
using "connect...". I think it is also better this way.
I recorded a video on installing and using the SharePoint Developer Explorer. See my first post for information on location for download and last changes. If the video below does not show follow this link to the video file.
See http://weblogs.asp.net/soever/archive/tags/SPDevExplorer/default.aspx for all myposts on SPDevExplorer.
There is a great project http://SPDevExplorer.codeplex.com by TheKid that allows you to edit SharePoint content from within Visual studio. This is especially handy when creating SharePoint Publishing sites where you are editing master pages and page layouts. Most people do this in SharePoint designer, hating the fact that SharePoint Designer messes with your code and sometimes locks files mysteriously. SPDevExplorer allows you to do this using Visual Studio using the great Visual Studio editor.
See http://weblogs.asp.net/soever/archive/tags/SPDevExplorer/default.aspx for all myposts on SPDevExplorer.
The release on codeplex is a bit old and had some issues so I decided to dive into the code and solve some issues. I published my first updated version as an Issue on the project, because that allowed me to add attachments. See http://spdevexplorer.codeplex.com/WorkItem/View.aspx?WorkItemId=7799 for the updated version. Both binaries and source code included.
The biggest changes I made:
- Https is now supported
- It is now possible to see and edit all files
I solved the following issues:
- Converted the project into a Visual Studio 2008 project
- Changed spelling error Domin into Domain, make some other texts consistant
- Generated a strong key for the SPDevExplorer.Solution project. I got an error when installing the WSP rthat assembly was not strong-signed.
- Cookies were retrieved on an empty cookies object, this lead to a object not found exception
- Several changes to make sure that https is supported by changing the UI that full path is shown in tree
- You now see https://mysite instead of just mysite.
- Added "Explore working folder..." on site, so the cache on the local file system can be found. Want to turn this into a feature to add files to the cache folders and be able to add these additional files.
- Added "Show info..." on files and folders, shows the cached xml info on the folder/file
- On delete file/folder, ask for confirmation
- On delete file/folder, refresh parent view to make sure it is correct again, make next node current, if not exist previous node
- Made keyboard interaction working, KeyPress was used, didn't work, now using KeyUp
- Del on keyboard now works correctly for deleting files/directories
- F5 on keyboard added for refresh. Parent folder is refreshed if on File, current folder is refreshed if on folder
- Removed (Beta) from name in window title
- Moved "SharePoint Explorer" from "View" menu to "Tools" menu, more appropriate place
- Option on site "Show all folders and files". Normally there is a list of hidden folders, but this also hides files you might want to edit like files in the forms folders of lists
- Removed adding list of webs to a site, gave an error and sites were never added. All sites must be added explicitly using "connect...". I think it is also better this way.
In a next post I will show some of the features of this great tool (video).
Note that it is not possible edit the web parts in web part pages with this tool (web parts are not part of the page), and that it is not possible to edit pages in the Pages document library, the actual content is managed in the meta data of the connected content type.
Thanks to Joe Cheng who was so kind to respond to my previous post on the topic I finally have LiveWriter working again against my blog.
The metablog handler needs to be: http://weblogs.asp.net/metablog.ashx
In the past this was: http://weblogs.asp.net/blogs/metablog.ashx, and it was changed without notification! At least I didn’t receive one!
Joe, thanks again! Time to get blogging again!
Developing SharePoint solutions is fun, especially with our Macaw Solutions Factory because we have all the tools to go from development to test to acceptation and to production. But then you want to make a modification to your version 1.0 SharePoint solution. How do you do that? We know how... with our Site Management Tool which is part of the Macaw solutions factory! Read all about our vision and concepts in the blogpost by my collegue Vincent hoogendoorn. Read Macaw Vision on SharePoint Release Management and let us know what you think of it.
Posts available so far on the Macaw Solutions Factory:
And if you are interested, tracks us on:
More Posts
Next page »