<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-8096263481091318859</atom:id><lastBuildDate>Fri, 06 Nov 2009 15:39:11 +0000</lastBuildDate><title>Adventures In SharePoint Land</title><description>This is a place to record my journey with SharePoint.  I realized that I was learning a lot of stuff that other people would probably like to know about (and that I would like to refer back to... I'm getting kinda old and my memory is fading.)</description><link>http://sharepoint.nailhead.net/</link><managingEditor>jefferydalton@hotmail.com (Jeff Dalton)</managingEditor><generator>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/AdventuresInMossLand" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7803490794799737613</guid><pubDate>Mon, 22 Jun 2009 00:54:00 +0000</pubDate><atom:updated>2009-06-21T20:54:30.180-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">SharePoint</category><title>SharePoint Saturday Charlotte</title><description>&lt;p&gt;This past Saturday I had the privilege of presenting at SharePoint Saturday Charlotte Event along side some top talent in the SharePoint community.&amp;#160; It was great to finally meet some of the people I follow on Twitter (too many to name).&amp;#160; Also, big kudos to &lt;strong&gt;Dan Lewis&lt;/strong&gt; &lt;a href="http://twitter.com/danlewisnet"&gt;&lt;font color="#800000"&gt;@danlewisnet&lt;/font&gt;&lt;/a&gt;, &lt;strong&gt;Brian Gough&lt;/strong&gt; and all of the #SPSCLT Volunteers, you guys/girls rock!!!&lt;/p&gt;  &lt;p&gt;As promised &lt;a href="http://www.slideshare.net/jefferydalton/spsclt-performance-testing-w-share-point" target="_blank"&gt;here&lt;/a&gt; the slide deck from my talk about Performance Testing with SharePoint.&amp;#160; I was hoping for a little bigger turnout, but when I saw I was in the same time slot as &lt;strong&gt;Becky Isserman&lt;/strong&gt; (&lt;a href="http://twitter.com/mosslover"&gt;&lt;font color="#800000"&gt;@MossLover&lt;/font&gt;&lt;/a&gt;) and &lt;strong&gt;Laura Rogers&lt;/strong&gt; (&lt;a href="http://twitter.com/wonderlaura"&gt;&lt;font color="#800000"&gt;@WonderLaura&lt;/font&gt;&lt;/a&gt;) I knew I would be lucky to get 7 people. :)&lt;/p&gt;  &lt;p&gt;I really enjoyed the sessions I got to attend.&amp;#160; &lt;/p&gt;  &lt;p&gt;The day started off with a GREAT presentation from Phil Wicklund. Phil had lots of pragmatic advice for managing your SharePoint investment.&amp;#160; &lt;/p&gt;  &lt;p&gt;Next, I learned a LOT about how MS has implemented Windows Azure from Rick Taylor (&lt;a href="http://twitter.com/slkrck"&gt;&lt;font color="#800000"&gt;@slkrck&lt;/font&gt;&lt;/a&gt;).&amp;#160; Rick is a GREAT speaker and had lots of war stories (which I LOVE hearing).&amp;#160; &lt;/p&gt;  &lt;p&gt;Then, I got to hear Mike Watson (@mikewat) talk about SharePoint hosting architectures.&amp;#160; He has some really good insight into what it takes to make SharePoint purr. Also, I got to hear that our hosting architecture for SharePoint is in line with what he thinks is the RIGHT way to do it.&lt;/p&gt;  &lt;p&gt;Next, I listened into Dan User (&lt;a href="http://twitter.com/usher"&gt;&lt;font color="#800000"&gt;@usher&lt;/font&gt;&lt;/a&gt;) talk about Taxonomies.&amp;#160; I felt much better about my Internet facing solution that will have about 30 Web Applications in one Farm after hearing what he is doing.&amp;#160; &lt;/p&gt;  &lt;p&gt;Finally, I listened to Dan Attis (&lt;a href="http://twitter.com/jdattis"&gt;&lt;font color="#800000"&gt;@jdattis&lt;/font&gt;&lt;/a&gt;) talk about a solution he recently wrapped up that used SharePoint lists to store data for a Web Interface that was not SharePoint.&amp;#160; It sounds like a really cool solution the folks at B&amp;amp;R built.&amp;#160; Also, I learned about &lt;a href="http://www.simple-talk.com/dotnet/.net-framework/.net-3.5-language-enhancements/" target="_blank"&gt;Object Initializers in .Net 3.5&lt;/a&gt;, really cool stuff. &lt;/p&gt;  &lt;p&gt; Definitely will not be my last SharePoint Saturday event.&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9be9df55-9ffa-431e-afa6-d32e457ecea7" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SharePoint+Saturday" rel="tag"&gt;SharePoint Saturday&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7803490794799737613?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/S0zEQTAZPQA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/S0zEQTAZPQA/sharepoint-saturday-charlotte.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2009/06/sharepoint-saturday-charlotte.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7159830372947138531</guid><pubDate>Fri, 05 Jun 2009 01:42:00 +0000</pubDate><atom:updated>2009-06-04T21:42:39.251-04:00</atom:updated><title>Big Thanks to Office / SharePoint Teams for TAP Airlift</title><description>&lt;p&gt;I had the privilege of attending the Office 14 TAP Air Lift this week in Seattle.&amp;#160; This is my second time coming out to to a SharePoint Air Lift and I must say they never disappoint.&amp;#160; While I cannot share any information from the Air Lift I can say it is exciting times to be working with SharePoint.&amp;#160; &lt;/p&gt;  &lt;p&gt;I really want to extend a big thank you to Microsoft for hosting a great event.&amp;#160; The folks in Office / SharePoint development teams have some big deadlines in front of them.&amp;#160; For them to take time out of their busy schedules to spend some one on one time with customers says a LOT.&amp;#160; &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7159830372947138531?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/h_Y1Kdy6NQo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/h_Y1Kdy6NQo/big-thanks-to-office-sharepoint-teams.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2009/06/big-thanks-to-office-sharepoint-teams.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-1970637292608280916</guid><pubDate>Sat, 16 May 2009 15:21:00 +0000</pubDate><atom:updated>2009-05-16T11:21:13.357-04:00</atom:updated><title>More Lessons learned from Performance Testing SharePoint</title><description>&lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Abstract&lt;/h4&gt;  &lt;p&gt;Performance testing with SharePoint, or any web based application, can be quite tricky.&amp;#160; Recently my team launched an upgraded Corporate Web Site based on SharePoint 2007.&amp;#160; The launch was quite challenging mainly due to mistakes made during performance testing &lt;a title="Lessons Learned from Intranet Launch" href="http://sharepoint.nailhead.net/2009/05/lessons-learned-from-launch-of-intranet.html" target="_blank"&gt;Lessons Learned from Intranet Launch&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;This post is dedicated to the lessons learned from the performance testing of Corporate Web Site.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Background&lt;/h4&gt;  &lt;p&gt;&lt;font color="#333333" size="2"&gt;Prior to launch we ran through our performance test scenarios 3 times.&amp;#160; Each time the output showed that we could scale way beyond the existing implantation of our Corporate Web Site (Referred to as Violin from here on).&amp;#160; &lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;The performance test scenarios had been chosen based on traffic patterns and pages determined to be high risk for performance (This was good).&amp;#160; &lt;/p&gt;  &lt;p&gt;Our key performance requirements stated that the web servers must support 38 page views / sec with response time &amp;lt; 5 sec (This was good).&amp;#160; This is a nice well defined requirement, although some could argue that 38 page views needs to be broken down into specific types of pages (ex. 10 home page views, 7 chapter page views, …).&amp;#160; &lt;/p&gt;  &lt;p&gt;We also had a performance goal stating that processor utilization should not go above 80% on web servers for more than 5 seconds (This was good).&lt;/p&gt;  &lt;p&gt;For the final test we replayed traffic from IIS logs that were taken during peak traffic window (when we received the most requests / sec).&amp;#160; This was a bit tricky because my Load Runner resource told me that this was not supported by Load Runner.&amp;#160; So he and I had to message the data inside the IIS logs to get it so Load Runner would support running the tests (this felt wrong at the time, but I cannot say if it is a mistake).&lt;/p&gt;  &lt;p&gt;We used Load Runner (sorry I do not know version) for all of the performance tests.&amp;#160; The Load Runner clients were located within the same data center as our web servers, but they were on different network segments.&lt;/p&gt;  &lt;p&gt;When we ran the tests we engaged several people from operations team (Network, Windows Server, SQL Server DBA and SharePoint Admin).&amp;#160; These people were tasked with monitoring components related to their area of expertise.&amp;#160; They were also required to collect performance statistics and report those back so they could be included in overall performance test report (This was good).&lt;/p&gt;  &lt;h4&gt;“Performance is exceptional” or The False Sense of Security&lt;/h4&gt;  &lt;p&gt;So each time we ran the tests we were able to reach levels of about 90 page views / sec on one server with avg. response time &amp;lt; 5 seconds (we have 4 load balanced WFE in our farm).&amp;#160; So we were hi-fiving and slapping each other on the back.&amp;#160; As far as we were concerned performance requirements were met, check them off we are done.&lt;/p&gt;  &lt;p&gt;We did notice an occasional spike w/ CPU, but we were able to correlate this back to pages expiring in Output Cache.&amp;#160; So this was not a concern.&lt;/p&gt;  &lt;p&gt;Well once we went live we discovered that something was gravely wrong.&lt;/p&gt;  &lt;h4&gt;So What Went Wrong&lt;/h4&gt;  &lt;p&gt;After going live we discovered that the output cache hit ratio was not aligned with the numbers we were seeing during performance testing.&amp;#160; So were were having a LOT less output cache hits.&amp;#160; This resulted in the servers having to do a lot more work than originally anticipated.&lt;/p&gt;  &lt;p&gt;What could have happened? We thought we did everything right with the performance tests.&amp;#160; What went wrong?&lt;/p&gt;  &lt;p&gt;Well after much soul searching (and re-reading basics of performance testing) it hit me.&amp;#160; &amp;quot;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Oh $hit we didn’t model user variations and think times.&amp;#160; &lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h5&gt;Does that really matter?&amp;#160; &lt;/h5&gt;  &lt;p&gt;Yeah it does, the reason is because we ran a high number of requests but the proportion of cached requests vs. un-cached requests was out of balance.&amp;#160; Had we have taken into consideration user think times and other variations(browser type, user location) we would have less hits against output cache.&lt;/p&gt;  &lt;p&gt;Classic 101 Performance Testing Mistake.&amp;#160; Oh well, you pick yourself up, dust yourself off and vow not to make the same mistake again.&lt;/p&gt;  &lt;h4&gt;Lessons Learned Summary&lt;/h4&gt;  &lt;h6&gt;&lt;font color="#333333" size="2"&gt;1. Think times matter&lt;/font&gt;&lt;/h6&gt;  &lt;p&gt;User think times are critical when doing performance testing (especially for web applications that rely on ASP.Net Output Caching to meet performance goals).&lt;/p&gt;  &lt;h6&gt;&lt;font color="#333333" size="2"&gt;2. End user variations matter&lt;/font&gt;&lt;/h6&gt;  &lt;p&gt;Just as important as think times you need to look at the IIS Logs (or your web analytics reports) to understand browser differences and local differences.&amp;#160; This is extremely critical if you have Output Cache configured so it treats these differences as non cached page requests.&lt;/p&gt;  &lt;h6&gt;&lt;font color="#333333" size="2"&gt;3. Mix up the IP addresses to fool user affinity&lt;/font&gt;&lt;/h6&gt;  &lt;p&gt;While this is not as important as Think Times and End User variations it is important if you are doing performance testing through a load balancer configured with session affinity.&amp;#160; &lt;/p&gt;  &lt;p&gt;All of the tests we ran looked like they were coming from 2 IPs.&amp;#160; While I cannot prove this invalidated the test results it looks like there was some sort of caching efficiencies realized somewhere in the stack (Switch, NIC, IIS, …).&amp;#160; &lt;/p&gt;  &lt;p&gt;References&lt;/p&gt;  &lt;p&gt;&lt;a title="Microsoft Patterns and Practices: Performance Testing Guidance for Web Applications" href="http://www.codeplex.com/PerfTestingGuide" target="_blank"&gt;Microsoft Patterns and Practices: Performance Testing Guidance for Web Applications&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a title="Microsoft Office Server Online: Configure page output cache settings" href="http://office.microsoft.com/en-us/sharepointserver/HA101206861033.aspx" target="_blank"&gt;Microsoft Office Server Online: Configure page output cache settings&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a title="MSDN: Output Caching and Cache Profiles" href="http://msdn.microsoft.com/en-us/library/aa661294.aspx" target="_blank"&gt;MSDN: Output Caching and Cache Profiles&lt;/a&gt;&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:c3ce8c8d-224e-4e54-98db-60b73857293a" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Performance+Testing" rel="tag"&gt;Performance Testing&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Load+Testing" rel="tag"&gt;Load Testing&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Lessons+Learned" rel="tag"&gt;Lessons Learned&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-1970637292608280916?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/Sz3COk0S9J0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/Sz3COk0S9J0/more-lessons-learned-from-performance.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2009/05/more-lessons-learned-from-performance.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7952914073932714106</guid><pubDate>Mon, 04 May 2009 00:55:00 +0000</pubDate><atom:updated>2009-05-03T21:02:20.086-04:00</atom:updated><title>Lessons Learned from Launch of Intranet on SharePoint 2007</title><description>&lt;h4&gt;Abstract&lt;/h4&gt;  &lt;p&gt;This post provides some lessons learned from the launch of our Corporate Intranet.&amp;#160; After about two weeks of poor performance and stability issues we stabilized the site and resolved most of the issues.&amp;#160; The lessons learned here are common and I'm sure our team was not the first (nor the last) to make these mistakes.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Background &lt;/h4&gt;  &lt;p&gt;Our Corporate Intranet supports about 21 Business Area / Business Units (BA/BUs).&amp;#160; When I say Intranet I am referring to a content publishing web site that provides announcements, latest news, corporate policies and other information that is important for employees to consider.&amp;#160; It is not a place for employees to collaborate as teams, this is done by another set of SharePoint 2007 sites.&lt;/p&gt;  &lt;p&gt;The Intranet is hosted on something we call the Common Web Platform (CWP).&amp;#160; What makes it common is it is one set of features / functionality that powers Intranet, Extranet and Internet publishing sites.&lt;/p&gt;  &lt;p&gt;In 2007 I started working on a project to upgrade CWP from its current infrastructure (SharePoint 2003 / MS Content Management Server 2002) to SharePoint 2007.&amp;#160; The first major component to rollout under the new SharePoint 2007 version of CWP is the Intranet site.&lt;/p&gt;  &lt;p&gt;Our intranet is not small. It contains approximately 67,000 webs, 65,0000 documents and 70,000 web pages.&amp;#160; The business requirements for sharing content between BA/BUs led us to determine that putting all this content in one site collection was the best choice.&amp;#160; I still believe this was the right decision, but it did cause us to create a SharePoint Content DB that is around 330 GB. &lt;/p&gt;  &lt;h4&gt;Launch Day&lt;/h4&gt;  &lt;p&gt;Launch day was actually quite calm from my perspective.&amp;#160; Yes we had a large site, but I felt we had done an excellent job with performance testing so launch would actually go quite smooth&amp;#160; I do not want to go into specifics but the performance testing done had shown that the new SharePoint 2007 site would be able to scale about 3 X higher in number of page views and users than the existing platform.&lt;/p&gt;  &lt;p&gt;Everything wasn't perfect, in fact far from it.&amp;#160; We had quite a number of lingering issues from content migration.&amp;#160; We also had some application bugs that just would not go away.&amp;#160; But everyone agreed that these could be solved so we decided to go forward with the launch.&lt;/p&gt;  &lt;p&gt;So at approximately noon Eastern US time on March 25th, 2009 we had the DNS team flip the switch and all traffic rolled off the old environment and to the new.&amp;#160; It was one of the smoothest cutover’s I have ever been associated with, I even heard some people saying that the did not know we had flipped the switch.&amp;#160; &lt;/p&gt;  &lt;p&gt;The next morning as Europe came online the proverbial $hit hit the fan.&amp;#160; I'm not going to go into the blow by blow details, but I will say a dedicated team of engineers that wanted nothing more than to see this new platform succeed went to work along with MS Premier Support.&amp;#160; On Tuesday April 7th the task force was closed as everyone agreed that while the new Intranet had some problems it was stable and performance was acceptable to end users.&lt;/p&gt;  &lt;p&gt;This was a really tough one to troubleshoot.&amp;#160; The thing that made it tough was just inconsistency with the crashes.&amp;#160; We could never tie it back to one specific event or one set of clear patterns.&amp;#160; The only consistency was the fact that it crashed during peak traffic loads (from 2 AM - 9 AM Eastern US time).&amp;#160; The Intranet availability dipped to about 60% during these two weeks.&lt;/p&gt;  &lt;h4&gt;Lessons Learned&lt;/h4&gt;  &lt;p&gt;As I stated after about two weeks of pure hell we got things stable.&amp;#160; During that time we did a lot of analysis and a few changes.&amp;#160; So in no particular order here is the things we changed and why and what I personally learned.&lt;/p&gt;  &lt;h5&gt;1. Hosting web services that do not use SharePoint inside your SharePoint Application Pool is bad (umm kay… South Park ref).&lt;/h5&gt;  &lt;p&gt;One of our field controls makes calls to a web service that in turn makes calls to a database to retrieve some data.&amp;#160; It is pretty basic stuff.&amp;#160; Well, to make a long story short the web service ended up in our SharePoint solution package and our field control ended up a call back into the same Application Domain to call some data from a database.&amp;#160; Yes, I know not a very smart thing to do.&lt;/p&gt;  &lt;p&gt;Anyway, during the performance we put together specific KPI’s to watch for this web service.&amp;#160; We saw no major problems with it, but put it on a list of things to change once the application went into maintenance mode.&lt;/p&gt;  &lt;p&gt;While we never linked any outages specifically to calls to this web service, however we did see a major improvement in overall stability when the web service was moved to a separate application pool.&amp;#160; &lt;/p&gt;  &lt;p&gt;So the lesson learned is to keep the Application Pools that host SharePoint sites dedicated to SharePoint sites (do not have those Application Pools host non SharePoint IIS Sites).&lt;/p&gt;  &lt;h5&gt;2. Be sure to set RowLimit on query at less than 5000 items to avoid table locks.&lt;/h5&gt;  &lt;p&gt;One of the problems that definitely caused outages was table locks at the SQL Server level.&amp;#160; We traced the table locks back to SQL that was being generated by a CAML query we used to show documents associated with a given web page.&amp;#160; &lt;/p&gt;  &lt;p&gt;SQL will lock a table if it thinks a query will return more than 5000 rows.&amp;#160; So it is very important that you set a row limit when using SPQuery and CrossListQueryCache objects.&amp;#160; When SharePoint generates the SQL for CrossListQuery if will set a default row limit of 2 million items.&amp;#160; I’m not sure if it does the same thing for SPQuery, but better safe than sorry.&amp;#160; &lt;/p&gt;  &lt;p&gt;So the lesson learned here is always set a row limit that is less than 5000 when using SPQuery and CrossListQueryCache.&amp;#160; &lt;/p&gt;  &lt;h5&gt;3. If querying by FileRef use SPWeb.GetListItem instead&lt;/h5&gt;  &lt;p&gt;The CAML Query referenced in Item 2 above was using FileRef field to filter the result list.&amp;#160; Unfortunately FileRef is a special field inside of SharePoint, meaning it doesn’t lend itself to be indexed (See Index List Field).&amp;#160; So the SQL query’s that were generated from the CAML were doing full table scans which is another big performance hit and can cause unwanted database locks.&lt;/p&gt;  &lt;p&gt;So in the end we abandoned using CAML query to get the documents and instead pulled them the SPWeb.GetListItem method.&amp;#160; At first there was a hugh debate on our team, because fundamentally it is better to reduce communication with DB.&amp;#160; So we were going from essentially one call to the DB to two calls per file in our document list field control (note: SPWeb.GetListItem results in at least 2 calls to the DB, one to get the List field info and one to pull the ListItem data).&lt;/p&gt;  &lt;p&gt;Our control has a limit of 200 documents that can be displayed.&amp;#160; So we knew the maximum number of times we would call GetListItem per page would be 200.&amp;#160; We also knew that the average number of documents per page was 3.&amp;#160; So most pages had very few documents to display.&lt;/p&gt;  &lt;p&gt;Our team is looking at alternate approaches.&amp;#160; One idea is to add a field to each document that has a GUID.&amp;#160; Then index that field and go back to doing queries using that new field.&amp;#160; We have a lot of testing to do before we make a decision to go in that direction.&lt;/p&gt;  &lt;p&gt;So the lesson learned was do not write CAML query's that use FileRef as the primary field to filter the results.&amp;#160; &lt;/p&gt;  &lt;h5&gt;4. Don't make these mistakes with performance testing.&lt;/h5&gt;  &lt;p&gt;Okay this one requires a separate blog post.&amp;#160; I promise to post a blog entry with this information very soon.&amp;#160; In the mean time I can say that the key mistake made with performance testing was not taking into consideration user sessions and think times.&amp;#160; We had the right URLs (we took these straight from logs of production machine), but we ran them through too fast which created a situation where URLs uses output cached versions of the pages when under normal load they would not have used the cached versions.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Wrapping Up&lt;/h4&gt;  &lt;p&gt;Granted we had a rough launch because the performance testing did not catch the critical application issues.&amp;#160; I do not want to leave people with the impression that everything we did was wrong.&amp;#160; Our team did a lot of stuff write and often these things get forgotten when things go wrong.&amp;#160; So here is a short list of the things we did right:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;We used 64 bit hardware for all our servers (SQL and Web Front Ends). &lt;/li&gt;    &lt;li&gt;We used the caching options with Publishing sites effectively (Output Cache, Object Cache and BLOB Cache). &lt;/li&gt;    &lt;li&gt;We discovered a major memory leak in our code with performance testing and fixed it before going live. &lt;/li&gt;    &lt;li&gt;We put together a well defined set of Solutions and Features for our application (so we can deploy easily). &lt;/li&gt;    &lt;li&gt;We created a team of people that have some really deep knowledge on building SharePoint Publishing sites. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;References&lt;/h4&gt;  &lt;p&gt;&lt;a title="MSDN: Best Practices: Common Coding Issues When Using the SharePoint Object Model" href="http://msdn.microsoft.com/en-us/library/bb687949.aspx" target="_blank" rel="nofollow"&gt;MSDN: Best Practices: Common Coding Issues When Using the SharePoint Object Model&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a title="Microsoft TechNet: Tune Web server performance (Office SharePoint Server)" href="http://technet.microsoft.com/en-us/library/cc298550.aspx" target="_blank" rel="nofollow"&gt;Microsoft TechNet: Tune Web server performance (Office SharePoint Server)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a title="SharePoint for End Users: Manage large SharePoint lists for better performance" href="http://sharepoint.microsoft.com/blogs/GetThePoint/Lists/Posts/Post.aspx?ID=162" target="_blank" rel="nofollow"&gt;SharePoint for End Users: Manage large SharePoint lists for better performance&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a title="Reza Alirezaei’s Blog: 20 key Points Arising, or Inferred, From “Working with large lists in MOSS 2007” Paper" href="http://blogs.devhorizon.com/reza/?p=790" target="_blank" rel="nofollow"&gt;Reza Alirezaei’s Blog: 20 key Points Arising, or Inferred, From “Working with large lists in MOSS 2007” Paper&lt;/a&gt;&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9b1d6af0-790e-472e-a580-d59b7e9781a4" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7952914073932714106?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/ZQ_HDztFHOA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/ZQ_HDztFHOA/lessons-learned-from-launch-of-intranet.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2009/05/lessons-learned-from-launch-of-intranet.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-405343132166352019</guid><pubDate>Fri, 01 May 2009 00:01:00 +0000</pubDate><atom:updated>2009-04-30T20:01:46.013-04:00</atom:updated><title>I'm Back...</title><description>&lt;p&gt;It's been a while since my last post.&amp;#160; &lt;/p&gt;  &lt;p&gt;I've been heads down in the middle of our corporate rollout of SharePoint 2007.&amp;#160; Specifically I have been working on project to upgrade our content management system from MCMS 2002 / SharePoint 2003 to SharePoint 2007.&amp;#160; Exciting stuff and every day presents new challenges.&lt;/p&gt;  &lt;p&gt;We just recently went live with our Intranet and now are starting work on Extranet and Internet sites.&amp;#160; &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-405343132166352019?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/N3MMV_LwOnU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/N3MMV_LwOnU/i-back.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2009/04/i-back.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7273510428134947748</guid><pubDate>Mon, 02 Jun 2008 02:29:00 +0000</pubDate><atom:updated>2008-06-01T22:29:59.598-04:00</atom:updated><title>Managing Key-Value Pair Settings in SharePoint</title><description>&lt;p&gt;Recently my team discussed various ways to manage application configuration settings in SharePoint.&amp;nbsp; We wanted to avoid using Web.Config files for Key-Value Pair data because of the complexity of managing this data in SharePoint.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#333333" size="2"&gt;SharePoint contains a decent API (SPWebConfigModification) for managing web.config settings across the farm.&amp;nbsp; It works pretty good, but we have had some trouble with it in certain situations.&amp;nbsp; If you are interested in a good article on SPWebConfigModification check out &lt;a href="http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32" target="_blank"&gt;this one by Mark Wagner&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Thankfully the folks on the SharePoint development team delivered just what we needed to have a simple solution for managing key-value pair settings.&amp;nbsp; It is the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.utilities.sppropertybag.aspx" target="_blank"&gt;SPPropertyBag&lt;/a&gt; class.&lt;/p&gt; &lt;p&gt;SharePoint provides a properties collection for SPFarm, SPWebApplication, SPWebService and SPWeb objects (none for SPSite, but site settings can be stored @ SPSite.RootWeb).&lt;/p&gt; &lt;p&gt;The properties collection for SPFarm, SPWebApplication and SPWebService are not really based on the SPPropertyBag class.&amp;nbsp; The properties collection comes from the derived class &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.sppersistedobject.aspx" target="_blank"&gt;SPPersistedObject&lt;/a&gt; and is actually a HashTable.&amp;nbsp; But it works exactly the same as SPPropertyBag.&lt;/p&gt; &lt;p&gt;It is really easy to manage the properties settings.&amp;nbsp; Here is some sample code to update settings for SPFarm, SPWebApplication or SPWebService.&lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetPropertyValue(SPPersistedObject spObject, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;)&lt;br /&gt;{                   &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (spObject.Properties.ContainsKey(name))&lt;br /&gt;    {&lt;br /&gt;        spObject.Properties[name] = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        spObject.Properties.Add(name, &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    spObject.Update();&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The SPWeb class actually uses SPPropertyBag for its properties.&amp;nbsp; The code to manage SPWeb.Properties is similar.&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetPropertyValue(SPWeb webSite, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (webSite.Properties.ContainsKey(name))&lt;br /&gt;    {&lt;br /&gt;        webSite.Properties[name] = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        webSite.Properties.Add(name, &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    webSite.Properties.Update();&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b8dd7a9a-7de0-4c68-bed9-42a9ef29188d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Key-Value%20Pair%20Settings" rel="tag"&gt;Key-Value Pair Settings&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Application%20Configuration%20Settings" rel="tag"&gt;Application Configuration Settings&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7273510428134947748?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/CcmyEMv3Dg8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/CcmyEMv3Dg8/managing-key-value-pair-settings-in.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/06/managing-key-value-pair-settings-in.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-5109713232127004804</guid><pubDate>Wed, 21 May 2008 05:28:00 +0000</pubDate><atom:updated>2008-05-21T01:28:21.673-04:00</atom:updated><title>Creating a SharePoint Web with the API</title><description>&lt;p&gt;I have been working on a application that provides a repeatable way to create sites.&amp;nbsp; This application is very similar to the &lt;a href="http://www.codeplex.com/sptdatapop" target="_blank"&gt;SharePoint Test Data Population Tool&lt;/a&gt;.&amp;nbsp; &lt;/p&gt; &lt;p&gt;One of the first tasks was to create new web applications.&amp;nbsp; A quick look at the API and I thought well this is simple enough.&lt;/p&gt; &lt;p&gt;First instantiate a new instance of SPWebApplicationBuilder.&amp;nbsp; Set some properties on my object and then call create.&amp;nbsp; Use the SPWebApplication.Provision() method and I am done.&lt;/p&gt; &lt;p&gt;Well that is not exactly true.&amp;nbsp; What I discovered was that the Provision method only creates the web application on the local server.&amp;nbsp; This is great for a single web front end, but for a more typical setup more work is required.&lt;/p&gt; &lt;p&gt;So I dug into the Administrative screens using &lt;a href="http://www.aisto.com/roeder/dotnet/" target="_blank"&gt;Reflector&lt;/a&gt;.&amp;nbsp; I discovered that the SharePoint team is instantiating a timer job that will provision the newly created web on the other web front ends.&lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (SPFarm.Local.TimerService.Instances.Count &amp;gt; 1)&lt;br /&gt;{&lt;br /&gt;       SPWebApplicationProvisioningJobDefinition definition = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SPWebApplicationProvisioningJobDefinition(application, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ApplicationPoolSection.ResetIis);&lt;br /&gt;       definition.Schedule = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SPOneTimeSchedule(DateTime.Now);&lt;br /&gt;       definition.Update();&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;So I thought okay this is simple enough. Then I discovered that SPWebApplicationProvisioningJobDefinition as marked as internal. Agghhhh!!!! &lt;/p&gt;&lt;br /&gt;&lt;p&gt;This pattern of finding a useful SharePoint routine only to have it hidden with the Internal keyword happens way too often.&amp;nbsp; I am sure that usually there is a good reason to hide away the functionality, but I could see no logical reason to hide SPWebApplicationProvisioningJobDefinition.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;So after throwing a few darts at the SharePoint Development Team dartboard (No I do not actually have one, but it could be a great gift SharePoint developers) I sat down and created a timer job definition that does basically the same thing as SPWebApplicationProvisioningJobDefinition.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This was the first timer job I had ever written so I made a *few* mistakes.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;First I failed to understand a basic concept of timer jobs.&amp;nbsp; That is any classes inheriting from &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spjobdefinition.aspx" target="_blank"&gt;SPJobDefinition&lt;/a&gt; need to be deployed to the GAC on each SharePoint server.&amp;nbsp; If they are not then the job will not be created correctly.&amp;nbsp; The frustrating thing I encountered was the fact that no runtime error was raised.&amp;nbsp; So it looked like the job definition was created correctly, but it was not.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Second I failed to put a default constructor on my job definition class.&amp;nbsp; This resulted in a runtime error with the job definition.&amp;nbsp; The runtime error indicated that the class failed to serialize properly.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Third I failed to decorate my member variables with the &lt;font size="2"&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.persistedattribute.aspx" target="_blank"&gt;[Persisted] attribute&lt;/a&gt;.&amp;nbsp;&amp;nbsp; This resulted in me losing my variable values.&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font size="2"&gt;Fourth I did not realize that I have to manually delete the job definitions when they fail.&amp;nbsp; To delete the timer job definition bring up the SharePoint Central Administration web site.&amp;nbsp; On the Operations tab choose Timer job definitions (under the Global Configuration header).&amp;nbsp; Next click the timer job definition in the list and then click the Delete button.&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Fifth I failed to understand that job definitions must be uniquely named.&amp;nbsp; This was a problem for me because my application would create one timer job per Web Application.&amp;nbsp; Sometimes a new web application job would be created before the other job was finished.&amp;nbsp; To work around the issue I included a timestamp in the name.&amp;nbsp; I am not sure if this was smart, but it works.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font size="2"&gt;Sixth I failed to understand that the OWSTimer.exe service must be restarted when deploying a new version of my timer job class library.&amp;nbsp; The OWSTimer.exe service is what manages the timer jobs.&amp;nbsp; It actually instantiates and executes the timer job classes.&amp;nbsp; Since my timer job class was deployed to the GAC it meant I had to restart the OWSTimer.exe (on each SharePoint server ughhh!!!).&amp;nbsp; &lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font size="2"&gt;In the end I accomplished my goal, but it would have been a lot easier if the SharePoint development team had not marked SPWebApplicationProvisioningJobDefinition as internal.&amp;nbsp; &lt;/p&gt;&lt;/font&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9db767d6-f6b0-48e0-9f1e-ab9a0a00394d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Timer%20Job" rel="tag"&gt;Timer Job&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-5109713232127004804?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/LsNHZodlwYM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/LsNHZodlwYM/creating-sharepoint-web-with-api.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/05/creating-sharepoint-web-with-api.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-1744236929861924122</guid><pubDate>Sun, 18 May 2008 17:27:00 +0000</pubDate><atom:updated>2008-05-18T13:27:28.173-04:00</atom:updated><title>What is going on in MOSS Land</title><description>&lt;p&gt;It has been a while since my last post.&amp;nbsp; I have been heads down working on a large project for my employer.&amp;nbsp; The project is to convert my employers existing MCMS/SharePoint 2003 solution to SharePoint 2007.&amp;nbsp; When this project is over my employer will have one of the largest SharePoint sites in the world.&lt;/p&gt; &lt;p&gt;Stay tuned, I am sure there will be many existing adventures to post about.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-1744236929861924122?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/GzjxeKGDZ6Q" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/GzjxeKGDZ6Q/what-is-going-on-in-moss-land.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/05/what-is-going-on-in-moss-land.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-2423524828008748052</guid><pubDate>Sun, 18 May 2008 17:19:00 +0000</pubDate><atom:updated>2008-05-18T13:19:44.792-04:00</atom:updated><title>Adventures in extending the Publishing.Fields.LinkValue class</title><description>&lt;p&gt;Recently I was working on a SharePoint application that required me to extend the out-of-box &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.publishing.fields.linkfieldvalue.aspx" target="_blank"&gt;Publishing Link field&lt;/a&gt;.&amp;nbsp; In the end I found an acceptable solution, but it took a little while to get there. &lt;/p&gt; &lt;h5&gt;&lt;font size="3"&gt;Inheriting from LinkFieldValue&lt;/font&gt; &lt;/h5&gt; &lt;p&gt;The first thing I tried was creating a new link field value class that extended the &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.publishing.fields.linkfieldvalue.aspx" target="_blank"&gt;LinkFieldValue&lt;/a&gt; class.&amp;nbsp; The LinkFieldValue class is not sealed so I thought I would be able to work with it. &lt;/p&gt; &lt;p&gt;LinkFieldValue inherits from the &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.publishing.fields.linkfieldvalue.aspx" target="_blank"&gt;HtmlTagValue&lt;/a&gt; class.&amp;nbsp; HtmlTagValue is more or less a dictionary that provides a structured way to create an HTML tag.&amp;nbsp; Unfortunately HtmlTagValue has all of the routines I needed marked as &lt;a href="http://msdn2.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx" target="_blank"&gt;Internal&lt;/a&gt;.&amp;nbsp; So this meant that my idea of inheriting from LinkFieldValue was dead.&lt;/p&gt; &lt;p&gt;The Publishing LinkFieldValue class inherits from the &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.publishing.fields.linkfieldvalue.aspx" target="_blank"&gt;Microsoft.SharePoint.Publishing.Fields.HtmlTagValue&lt;/a&gt; class.&amp;nbsp; If you look at the guts of LinkFieldValue you will see that HtmlTagValue does all the heavy lifting.&amp;nbsp; The LinkFieldValue properties call back into the HtmlTagValue.Item property.&amp;nbsp; &lt;/p&gt; &lt;p&gt;HtmlTagValue class has two public routines (everything else is Internal or private). So that pretty much ended my idea of extending the LinkFieldValue class.&amp;nbsp; &lt;/p&gt; &lt;h5&gt;&lt;strong&gt;&lt;font size="3"&gt;Storing link data in SPFieldMultiColumnValue field&lt;/font&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Next I decided to store the link data in a SPFieldMultiColumnValue field.&amp;nbsp; I have created plenty of these in the past so I knew exactly what to do.&lt;/p&gt; &lt;p&gt;Everything was great until I ran a test for Link fix-up.&lt;/p&gt; &lt;p&gt;&lt;em&gt;In case you did not know WSS has built-in functionality that supports fixing site collection links that get broken because the WSS object (image, document, publishing page) is moved.&amp;nbsp; &lt;/em&gt;&lt;/p&gt; &lt;p&gt;Turns out WSS link fix-up only works for certain field types (and Text is not one of them).&amp;nbsp; It also requires that the link be stored as an &amp;lt;A&amp;gt; anchor tag.&amp;nbsp; So that pretty much ended my idea of using the SPFieldMultiColumnValue field.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font size="3"&gt;Using XML to store the Link data&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Finally I decided to store the link using the same technique as the &lt;a href="http://office.microsoft.com/en-us/sharepointserver/HA101551681033.aspx" target="_blank"&gt;Summary Link control&lt;/a&gt;.&amp;nbsp; The Summary Link control provides a way of storing a variable number of links in a publishing field.&amp;nbsp; It does this by serializing the data into XHTML and storing it in a rich text field.&lt;/p&gt; &lt;p&gt;First I created a base field class that would act as a parent for any field that I wanted to store as XHTML.&amp;nbsp; &lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; XmlAsHtmlField : SPFieldMultiLineText&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XmlAsHtmlField(SPFieldCollection fields, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; fieldName) : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(fields, fieldName) { }&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XmlAsHtmlField(SPFieldCollection fields, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; typeName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; displayName) : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(fields, typeName, displayName) &lt;br /&gt;  {&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.RichText = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;br /&gt;     &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.SetRichTextMode(SPRichTextMode.FullHtml);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Next I created a XmlAsHtmlFieldValue class that would act as a base class for all field values that use the XmlAsHtmlField class.&amp;nbsp; The base field value class implements a dictionary that provides a mechanism for all child classes to store their property values.&amp;nbsp; The class assumes that any properties stored in the dictionary translate their value into XHTML.&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; XmlAsHtmlValue&lt;br /&gt;{&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, XmlStorageItem&amp;gt; storageItems = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, XmlStorageItem&amp;gt;();&lt;br /&gt;       &lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// Initializes the XmlAsHtmlValue class&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XmlAsHtmlValue()&lt;br /&gt;   {&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// Initializes the XmlAsHtmlValue class and populates the Dictionary based on the provided XML&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;param name="HtmlValue"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XmlAsHtmlValue(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; HtmlValue)&lt;br /&gt;   {&lt;br /&gt;      HtmlValue = Utility.FixQuotesInXML(HtmlValue);&lt;br /&gt;&lt;br /&gt;      System.Xml.XmlDocument xmlDocument = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlDocument();&lt;br /&gt;      xmlDocument.LoadXml(HtmlValue);&lt;br /&gt;      XmlNodeList storageItemNodes = xmlDocument.SelectNodes(&lt;span style="color: #006080"&gt;"/div/div"&lt;/span&gt;);&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (XmlNode storageItemNode &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; storageItemNodes)&lt;br /&gt;      {&lt;br /&gt;         XmlAttribute classValue = storageItemNode.Attributes[&lt;span style="color: #006080"&gt;"class"&lt;/span&gt;];&lt;br /&gt;         &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; id = storageItemNode.Attributes[&lt;span style="color: #006080"&gt;"id"&lt;/span&gt;].Value;&lt;br /&gt;         XmlStorageItemType itemType = (XmlStorageItemType)System.Enum.Parse(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(XmlStorageItemType), classValue.Value);&lt;br /&gt;         storageItems.Add(id, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlStorageItem(itemType, storageItemNode.InnerXml, id));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// Returns the dictionary that is used to store properties&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, XmlStorageItem&amp;gt; StorageItems&lt;br /&gt;   {&lt;br /&gt;      get&lt;br /&gt;      {&lt;br /&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; storageItems;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// Creates an XML representation of the Dictionary&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #008000"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;virtual&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ToXml()&lt;br /&gt;   {&lt;br /&gt;      StringBuilder returnValue = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;      returnValue.Append(&lt;span style="color: #006080"&gt;"&amp;lt;div id=\"root\"&amp;gt;"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (KeyValuePair&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, XmlStorageItem&amp;gt; item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; storageItems)&lt;br /&gt;      {&lt;br /&gt;         XmlStorageItem storageItem = item.Value;&lt;br /&gt;         returnValue.AppendFormat(&lt;span style="color: #006080"&gt;"&amp;lt;div id=\"{0}\" class=\"{1}\"&amp;gt;{2}&amp;lt;/div&amp;gt;"&lt;/span&gt;, storageItem.ID, storageItem.StorageItemType, storageItem.StorageItemValue);&lt;br /&gt;      }&lt;br /&gt;      returnValue.Append(&lt;span style="color: #006080"&gt;"&amp;lt;/div&amp;gt;"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; returnValue.ToString();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ToString()&lt;br /&gt;   {&lt;br /&gt;      &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ToXml();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;One really ugly problem I ran into was the fact that Microsoft will strip out double and single quotes from the HTML.&amp;nbsp; I am not sure why this is done, but I had to create a routine to put the quotes back in.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Next I created an extended link value class that used the out-of-box link field value plus another class I created with the new link properties.&amp;nbsp; I stored both of the classes in the XMLAsHtmlValue class. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Because I used the out-of-box Link Value class I ran into some problems when I created unit tests.&amp;nbsp; When I tried to generate the tests in Visual Studio.Net 2008 I would receive the following error.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;Could not resolve member reference: Microsoft.SharePoint.ISPConversionProcessor::PostProcess&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To fix the problem I added the following DLL as a reference in my project (Microsoft.HtmlTrans.Interface, it is located in the GAC)&lt;/p&gt;&lt;br /&gt;&lt;h5&gt;Parting Thoughts&lt;/h5&gt;&lt;br /&gt;&lt;p&gt;In the end I had something that would allow me to create fairly extensible field value classes.&amp;nbsp; I am not sure how well this solution scales (a topic for a future posting) and I am not how easy this solution will be to upgrade with future versions of SharePoint.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-2423524828008748052?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/7d1-mfz2wSw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/7d1-mfz2wSw/adventures-in-extending.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/05/adventures-in-extending.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-8075486329644331463</guid><pubDate>Sat, 03 May 2008 01:09:00 +0000</pubDate><atom:updated>2008-05-02T21:09:21.349-04:00</atom:updated><title>Problems with XMLNS and SPWebConfigModification</title><description>&lt;p&gt;Recently I posted an article that discussed the SPWebConfigModification.&amp;#160; I meant to add some information about problems with XML Namespaces and SPWebConfigModification.&lt;/p&gt;  &lt;p&gt;One of the first problems my team encountered with SPWebConfigModification was failures when working with configuration settings that overrode the default xml namespace (xmlns).&lt;/p&gt;  &lt;p&gt;The problem arose when we tried to apply the webconfig modifications needed to for the Enterprise Library.&amp;#160; Below is a sample entry from the configuration settings needed for Enterprise Library.&amp;#160; Notice how the default xmlns is being overridden.&lt;/p&gt;  &lt;div&gt;   &lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;enterpriselibrary.configurationSettings&lt;/span&gt; applicationName=&amp;quot;NewsApplication&amp;quot; xmlns:xsd=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot; xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot; xmlns=&amp;quot;http://www.microsoft.com/practices/enterpriselibrary/08-31-2004/configuration&amp;quot; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;That one statement invalidates the XPath expressions in the SPWebConfigModification Name and Path properties.&amp;#160; This means that SPWebConfigModification cannot successfully find the entry when it scans the web.config file.&amp;#160; So every time the web.config file is modified by SPWebConfigModification the entry gets duplicated (which causes the web.config file to be invalid).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;A little research into the way .Net Framework handles XML namespaces turned up the XmlNameSpaceManager class.&amp;#160; This class is used to define namespaces at runtime.&amp;#160; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Unfortunately SPWebConfigModification does not expose this class when defining the XPath expressions.&amp;#160; If it did it would be possible to work with XML namespaces.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;By the way, the team was able to work around the enterprise library configuration problem by moving the EntLib configuration settings into separate files.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:09616cb6-2467-4344-a9f2-298415c8e17e" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Xml" rel="tag"&gt;Xml&lt;/a&gt;,&lt;a href="http://technorati.com/tags/configuration%20management" rel="tag"&gt;configuration management&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-8075486329644331463?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/Qng6zArm-yU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/Qng6zArm-yU/problems-with-xmlns-and.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/05/problems-with-xmlns-and.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-6246297949893089308</guid><pubDate>Fri, 02 May 2008 03:56:00 +0000</pubDate><atom:updated>2008-05-02T21:12:32.925-04:00</atom:updated><title>Creating a Feature to update the Web.Config</title><description>&lt;p&gt;I just wrapped up a feature that will update the web.config with custom settings. I did it by creating a feature receiver that loads web.config modifications from an xml configuration file and then applies them using the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebconfigmodification.aspx" target="_blank"&gt;SPWebConfigModification&lt;/a&gt; class. &lt;/p&gt;  &lt;p&gt;The entire process is straight forward. There are few subtle nuisances to SPWebConfigModification that make it tricky.&lt;/p&gt;  &lt;h3&gt;&lt;span style="color: #000000"&gt;Creating New Web.Config Changes&lt;/span&gt;&lt;/h3&gt;  &lt;p&gt;Below is some sample code from my Feature. The ApplyWebConfigChange is responsible for creating an entry to the web.config.&lt;/p&gt;  &lt;div&gt;   &lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ApplyWebConfigChange(SPWebApplication webApp, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ConfigurationChangeIdentifier, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ConfigurationName, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ConfigurationXPath, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ConfigurationValue)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    Collection&amp;amp;lt;SPWebConfigModification&amp;amp;gt; modsCollection = webApp.WebConfigModifications;&lt;br /&gt;&lt;br /&gt;    SPWebConfigModification configMod = LookupModificationEntry(modsCollection, ConfigurationChangeIdentifier, ConfigurationName, ConfigurationXPath);&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (configMod == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        configMod = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SPWebConfigModification(ConfigurationName, ConfigurationXPath);&lt;br /&gt;        configMod.Owner = ConfigurationChangeIdentifier;&lt;br /&gt;        configMod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;&lt;br /&gt;        modsCollection.Add(configMod);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    configMod.Value = ConfigurationValue;&lt;br /&gt;    webApp.Farm.Services.GetValue&amp;amp;lt;SPWebService&amp;amp;gt;().ApplyWebConfigModifications();&lt;br /&gt;    webApp.Update();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The first step is to reference the collection that contains a list of SPWebConfigModification objects. This collection is accessed via the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebapplication.webconfigmodifications.aspx" target="_blank"&gt;SPWebApplication.WebConfigModifications&lt;/a&gt; property.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The next step is to see if the change already exists in the WebConfigModifications collections. If it does then all I want to do is update it. If it is not there then I want to create it.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;When creating new entries it is extremely important to make sure the SPWebConfigModification.Name is unique within the SPWebConfigModification.Path. If the name is not unique within the context of the path then you could end up with duplicate entries and you will not be able to remove the entry with SPWebConfigModification.&lt;br /&gt;  &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  &lt;p&gt;&lt;span style="font-size: 85%; color: #333333"&gt;Tip: Get very comfortable with XPath since both the Path property and Name property have to be valid XPath syntax. &lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Make sure the Owner property is set to a unique value for your change. Later I will provide a quick and easy way to remove changes from SPWebConfigModification collection. My technique assumes that the Owner is unique for each modification.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  &lt;p&gt;&lt;span style="font-size: 85%; color: #333333"&gt;Tip: Always set Type property to &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebconfigmodification.spwebconfigmodificationtype.aspx" target="_blank"&gt;SPWebConfigModification.SPWebConfigModificationType&lt;/a&gt;.EnsureChildNode. The two other options &amp;quot;EnsureAttribute&amp;quot; and &amp;quot;EnsureSection&amp;quot; will permanently change the web.config (&lt;strong&gt;as in you can never remove the items, even if you manually remove them they will return&lt;/strong&gt;)&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The last step is to call the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applywebconfigmodifications.aspx" target="_blank"&gt;SPWebService.ApplyWebConfigModifications&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms452881.aspx?PHPSESSID=ca9tbhkv7klmem4g3b2ru2q4d4" target="_blank"&gt;SPWebApplication.Update&lt;/a&gt;. Since my web application is deployed across multiple web front ends I need to call the ApplyWebConfigModifications. This routine will make sure the web.config change is made on all web front ends. If I only had one web front end then I could have just called SPWebApplication.Update.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Removing Web.Config Changes&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Removing entries is really simple if you can assume that the Owner property is unique per change. In the routine below you can see that I will go through each item in the SPWebConfigModification. When I find an entry with the Owner set to a certain value I will remove it.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;  &lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; RemoveWebConfigChange(SPWebApplication webApp, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ConfigurationChangeIdentifier)&lt;br /&gt;{&lt;br /&gt;   &lt;br /&gt;    Collection&amp;lt;SPWebConfigModification&amp;gt; modsCollection = webApp.WebConfigModifications;&lt;br /&gt;&lt;br /&gt;    SPWebConfigModification deleteModification = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (SPWebConfigModification mod &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; modsCollection)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (mod.Owner == ConfigurationChangeIdentifier)&lt;br /&gt;        {&lt;br /&gt;            deleteModification = mod;&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (deleteModification != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        modsCollection.Remove(deleteModification);&lt;br /&gt;        webApp.Farm.Services.GetValue&amp;amp;lt;SPWebService&amp;amp;gt;().ApplyWebConfigModifications();&lt;br /&gt;        webApp.Update();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Here is an &lt;a href="http://blogs.devhorizon.com/reza/?p=459" target="_blank"&gt;article&lt;/a&gt; that covers some more problems with SPWebConfigModification in more detail. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I learned a lot of great information about SPWebConfigModification &lt;a href="http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d325ca7c-cc53-48cc-9ffd-680af2b15ae5" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Configuration%20Management" rel="tag"&gt;Configuration Management&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-6246297949893089308?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/npIHpVd0y6c" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/npIHpVd0y6c/creating-feature-to-update-webconfig.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/05/creating-feature-to-update-webconfig.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-4460826507763823956</guid><pubDate>Wed, 30 Apr 2008 01:24:00 +0000</pubDate><atom:updated>2008-04-29T21:24:23.555-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">SharePoint</category><title>Instrumentation &amp; Logging for SharePoint (Part 1)</title><description>&lt;p&gt;Recently I have been defining how the development team will implement Instrumentation and Logging for SharePoint.&amp;#160; I looked at a lot of different options and settled on the built-in .Net Framework diagnostic routines.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Logging&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;For logging I decided to use the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.tracesource.aspx" target="_blank"&gt;System.Diagnostics.TraceSource&lt;/a&gt; class.&amp;#160; This class was introduced with .Net Framework 2 and is a marked improvement over the original System.Diagnostics.Trace (my opinion).&amp;#160; &lt;/p&gt;  &lt;p&gt;Out-of-Box System.Diagnostics has trace listeners for Event Log, Console and File System.&amp;#160; For grins I wrote a listener that will write to the SharePoint log system.&amp;#160; It was very easy since the WSS SDK contains an &lt;a href="http://msdn2.microsoft.com/en-us/library/aa979590.aspx" target="_blank"&gt;example&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Three really nice features I like about the improved Diagnostics tracing classes are: &lt;a href="http://msdn2.microsoft.com/en-us/library/a10k7w6c(VS.80).aspx" target="_blank"&gt;Trace Options&lt;/a&gt;, &lt;a href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.sourcelevels.aspx" target="_blank"&gt;Source Levels&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.tracefilter.aspx" target="_blank"&gt;Trace Filters&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Trace Options provide a nice flexible way of indicating what data should be written along with the log message.&amp;#160; Some examples include: Call Stack, Date &amp;amp; Time stamps, Thread ID, Process ID and Logical Call Stack.&amp;#160; These options can be configured in the configuration file so the application does not need to even know about them.&lt;/p&gt;  &lt;p&gt;Source Levels provide a nice alternative to the old Trace Switch class.&amp;#160; A source level determines what type of messages should be logged (i.e. Critical, Error, All, ...).&lt;/p&gt;  &lt;p&gt;Trace Filters provide a way to tell the Listener what types of errors it should log.&amp;#160; This is really nice because it means that I can create File System listener that will write out every messages passed on by the Trace Source.&amp;#160; At the same time my Trace Source could have an Event Log listener that still only writes critical messages to the Event Log.&lt;/p&gt;  &lt;p&gt;The really great thing is all of these classes can be configured in a configuration file.&lt;/p&gt;  &lt;p&gt;Below is a sample configuration I used while working with the Trace classes.&lt;/p&gt;  &lt;div&gt;   &lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;system.diagnostics&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;trace&lt;/span&gt; &lt;span style="color: #ff0000"&gt;autoflush&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;sources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;source&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;MyLogSource&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;switchValue&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;All&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;listeners&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;consoleListener&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;fileListener&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;eventLogListener&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;sharepointLogListener&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;listeners&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;source&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;sources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;        &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;sharedListeners&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;consoleListener&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;System.Diagnostics.ConsoleTraceListener&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;fileListener&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;initializeData&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;c:\temp\VolvoCWP.txt&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;System.Diagnostics.TextWriterTraceListener&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;traceOutputOptions&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;DateTime,ProcessId,LogicalOperationStack&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;filter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;System.Diagnostics.EventTypeFilter&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;initializeData&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;All&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;eventLogListener&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;System.Diagnostics.EventLogTraceListener&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;traceOutputOptions&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;DateTime,ProcessId,LogicalOperationStack&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;initializeData&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;JD Application&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;filter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;System.Diagnostics.EventTypeFilter&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;initializeData&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Critical&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;sharepointLogListener&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;MyLogListener.SharePointTraceListener, MyLogListener, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6bb1c46a01dcf0a2&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ApplicationName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;JeffD&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ProductName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;JeffD&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;CategoryName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Runtime&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;                &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;sharedListeners&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;        &lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;system.diagnostics&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This configuration contains one Trace Source (MyLogSource).&amp;#160; It is configured to log all messages that are logged with it (switchValue=&amp;quot;All&amp;quot;).&amp;#160; It has four listeners it will use to log the message (yes the message can get logged into four places... not very practical in the real world). The consoleListener, fileListener and sharepointLogListener are configured with filters that tell them to log every message.&amp;#160; The eventLogListener is configured to only log messages marked as Critical.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The SharePointTraceListner was actually very simple to write.&amp;#160; I was able to find a really great &lt;a href="http://msdn.microsoft.com/en-us/library/aa979522.aspx" target="_blank"&gt;example&lt;/a&gt; of writing to the SharePoint log inside the WSS SDK.&amp;#160; All I did was take that example and plug it into a standard Trace Listener.&amp;#160; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:a9ea0de9-370d-4721-b116-79258d257e0b" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Logging" rel="tag"&gt;Logging&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.Net%20Framework" rel="tag"&gt;.Net Framework&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-4460826507763823956?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/faLFoFsbblU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/faLFoFsbblU/instrumentation-logging-for-sharepoint.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/instrumentation-logging-for-sharepoint.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-4205288639346774534</guid><pubDate>Fri, 25 Apr 2008 01:13:00 +0000</pubDate><atom:updated>2008-04-24T21:13:47.871-04:00</atom:updated><title>Test Driven Development with SharePoint</title><description>&lt;p&gt;Lately I have been doing quite a bit of development inside of SharePoint.&amp;nbsp; I am a big fan of Test Driven Development so naturally I wanted to carry over one of my favorite development techniques to SharePoint.&lt;/p&gt; &lt;p&gt;I wanted to share some of the obstacles I ran into along the way and techniques I used to overcome them.&lt;/p&gt; &lt;p&gt;Before I go on I want to point out that I am using Visual Studio 2008 for my development environment.&amp;nbsp; &lt;/p&gt; &lt;h3&gt;&lt;font color="#000000"&gt;Missing Method Exception&lt;/font&gt;&amp;nbsp;&lt;/h3&gt; &lt;p&gt;One of the first problems I encountered was a Missing Method Exception when I would run the unit tests.&amp;nbsp; I never did really find out what was happening.&amp;nbsp; I did find a nice technique for working around it.&amp;nbsp; &lt;/p&gt; &lt;p&gt;I modified the PostBuild routine of my Unit Tests to install my target DLL in the GAC.&amp;nbsp; I also executed my tests in Debug mode.&amp;nbsp; Doing both things overcame the issues.&amp;nbsp; You can read the details &lt;a href="http://sharepoint.nailhead.net/2008/04/missing-method-exception-or-why-my-unit.html" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;&lt;font color="#000000"&gt;Testing Routines that require HTTPRuntime context&lt;/font&gt;&lt;/h3&gt; &lt;p&gt;The next big challenge for me was to find a way to test routines that needed the HTTPRuntime, HTTPContext or SPContext objects.&lt;/p&gt; &lt;p&gt;I'm not a big fan of using mock objects when unit testing.&amp;nbsp; And the thought of mocking any of those classes (or any of the SharePoint classes) turns my stomach.&amp;nbsp; &lt;/p&gt; &lt;p&gt;For the most part my routines are built so they do not require runtime context.&amp;nbsp; If I had to guess I would say &amp;lt; 5% of my tests are setup this way.&amp;nbsp; Even though it is such a small part of my test footprint it is still a very important part.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Since I am using Visual Studio 2008 (this was available in VS.Net 2005 too) I am able to decorate those tests that require context with the HostType and UrlToTest attributes.&amp;nbsp; Using these attributes will tell MSUnit to run my tests within the context of the IIS runtime.&lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;[TestMethod()]&lt;br /&gt;[HostType(&lt;span style="color: #006080"&gt;"ASP.Net"&lt;/span&gt;)]&lt;br /&gt;[UrlToTest(&lt;span style="color: #006080"&gt;"Url to SharePoint Page"&lt;/span&gt;]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; FooBarTest&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; expected = &lt;span style="color: #006080"&gt;"raBooF"&lt;/span&gt;;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; actual = MySharePointRoutine.RoutineThatUsesSPContext();&lt;br /&gt;    Assert.AreEqual(expected, actual);&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This works great, but there are some drawbacks.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;1. Requires SharePoint site to be configured with Full trust&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For MSUnit to hook into the IIS runtime context it has to do some tricky stuff.&amp;nbsp; Unfortunately it doesn't work unless you configure the SharePoint site Full Trust.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;One could argue that this invalidates my Unit Tests since it is quite possible that I will have some code that executes one way under Full Trust and another under WSS_Minimal Trust.&amp;nbsp; While this is true I believe the chance of this happening is small.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;2. Does not work with Publishing Pages&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If you try to use a publishing page in the UrlToTest attribute the test will fail.&amp;nbsp; Below is the error message.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;&lt;span lang="en-us"&gt;The Web request 'SharePoint URL&lt;a href="http://usgson1100/mytest2/pages/MyTestCodeBehind.aspx'" target="_blank"&gt;&lt;font color="#0068cf"&gt;'&lt;/font&gt;&lt;/a&gt; completed successfully without running the test. This can occur when configuring the Web application for testing fails (an ASP.NET server error occurs when processing the request), or when no ASP.NET page is executed (the URL may point to an HTML page, a Web service, or a directory listing). Running tests in ASP.NET requires the URL to resolve to an ASP.NET page and for the page to execute properly up to the Load event. The response from the request is stored in the file 'WebRequestResponse_RelatedLinkPathTest_.html' with the test results; typically this file can be opened with a Web browser to view its contents.&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;&lt;span lang="en-us"&gt;I do not know exactly what this means, but I believe the problem may be caused by the fact that Publishing pages are virtual pages that map directly to a list item (i.e. they are not actually an ASPX page). &lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;This kind of stinks because some of the tests may expect the SPContext.Current.ListItem property to be loaded with a valid list item.&amp;nbsp; As a work around I discovered that I could could use the URL that will display list properties for a publishing page (Pages/Forms/DispForm.aspx?ID={List ID}).&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;&lt;font color="#333333"&gt;To find create the DispForm Url I will first open a browser and point to /pages/forms/allitems.aspx (where pages represents the Publishing pages list).&amp;nbsp; This will provide a list of all of the pages.&amp;nbsp; I then choose the item I want and select View Properties.&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;&lt;a href="http://lh4.ggpht.com/jeffdalton1/SBEwSYnp2dI/AAAAAAAAAB4/0Ke2TaKqkME/s1600-h/DispForm%5B6%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="262" alt="DispForm" src="http://lh6.ggpht.com/jeffdalton1/SBEwS4np2eI/AAAAAAAAACA/9fjDooQK7H4/DispForm_thumb%5B4%5D.jpg?imgmax=800" width="455" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;Then I copy the URL from the web browser and I have what I need.&lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;&lt;strong&gt;3. Difficult for Team Environments&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;Another problem is the fact that it is not possible (or I could never find a way) to parameterize the UrlToTest attribute.&amp;nbsp; This means that the URL must be generalized so it works on all of the developer and build machines.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p dir="ltr"&gt;Microsoft has a great article that discusses issues teams will encounter when testing web pages (&lt;a href="http://msdn2.microsoft.com/en-us/library/ms243136(VS.80).aspx" target="_blank"&gt;here&lt;/a&gt;).&amp;nbsp; The article discuss's using the AspNetDeveloperServerHost attribute in the MSUnit.&amp;nbsp; This attribute supports context parameters so tests can be made to work across teams.&amp;nbsp; Unfortunately I was not able to AspNetDevelpoerServerHost to work with SharePoint Url's.&amp;nbsp; When you think about all of the infrastructure needed to make WSS work it is not surprising that this does not work.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Conclusions&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Test Driven Development with SharePoint is doable.&amp;nbsp; The difficulties of setting up Unit Tests will vary depending on what your tests need to do.&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b6ac4f1a-fec0-4210-b9a2-c3c11974ae07" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Test%20Driven%20Development" rel="tag"&gt;Test Driven Development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Visual%20Studio%202008" rel="tag"&gt;Visual Studio 2008&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-4205288639346774534?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/CR7ehUSjXLM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/CR7ehUSjXLM/test-driven-development-with-sharepoint.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/test-driven-development-with-sharepoint.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-8488002346981734109</guid><pubDate>Fri, 18 Apr 2008 02:57:00 +0000</pubDate><atom:updated>2008-04-17T23:00:12.795-04:00</atom:updated><title>Creating a Rendering Template that supports Edit and Display modes</title><description>&lt;p&gt;I have been working on a Field Control rendering template that works for both Edit and Display modes.&amp;nbsp; Along the way I learned quite a few things.&lt;/p&gt; &lt;p&gt;First I am not covering the steps to create a SharePoint field control.&amp;nbsp; You can find a walk-through for creating a custom field control &lt;a href="http://msdn2.microsoft.com/en-us/library/aa981226.aspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;h2&gt;&lt;/h2&gt; &lt;h5&gt;DefaultTemplateName is not used in Display mode.&lt;/h5&gt; &lt;p&gt;The first problem I ran into was the rendering of my control in Display mode.&amp;nbsp; I had put in an override for the &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.templatebasedcontrol.defaulttemplatename.aspx" target="_blank"&gt;DefaultTemplateName&lt;/a&gt; property in my control.&amp;nbsp; The documentation was vague but seemed to imply that the Display rendering template would be pulled from this value. &lt;/p&gt; &lt;p&gt;Well that is not the case.&amp;nbsp; To get my custom rendering template loaded in Display mode I had to override the &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.basefieldcontrol.displaytemplatename.aspx" target="_blank"&gt;DisplayTemplateName&lt;/a&gt; property.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Once I had both DefaultTemplateName and DisplayTemplateName overridden I was in full control of the display.&lt;/p&gt; &lt;h5&gt;Mixing the TemplateContainer and EditModePanel objects&lt;/h5&gt; &lt;p&gt;With my rendering template I thought it would be best to just create one rendering template for both Edit and Display modes.&amp;nbsp; The main reason I did this was so I could encapsulate all of the markup for a control in one rendering template.&amp;nbsp; &lt;/p&gt; &lt;p&gt;My rendering template was nothing more than a ASP.Net User Control (ASCX file).&amp;nbsp; By using a user control I had a nice container to edit the HTML mark-up for my control.&lt;/p&gt; &lt;p&gt;To give myself different looks for Edit and Display modes I decided to use the Publishing &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.publishing.webcontrols.editmodepanel.aspx" target="_blank"&gt;EditModePanel&lt;/a&gt; control.&amp;nbsp; EditModePanels are a nice way of isolating a set of mark-up based on the page mode.&amp;nbsp; &lt;/p&gt; &lt;p&gt;I put my EditModePanel controls inside my &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.renderingtemplate.aspx" target="_blank"&gt;RenderingTemplate&lt;/a&gt; control.&amp;nbsp; This is very important because it caused me grief later on.&lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 102.4%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; height: 110px; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;SharePoint:RenderingTemplate&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="VolvoCWPRelatedLinkControl"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Template&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;    &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;SharePointPublishing:EditModePanel&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="RelatedLinkEditPanel"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;PageDisplayMode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Edit"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;SuppressTag&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="true"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the CreateChildControls routine of my control I needed to instantiate classes that were mapped to the controls in my ASCX file.&amp;nbsp; According to the walk-through sample I should use the TemplateContainer.FindControl routine.&amp;nbsp; Well this did not work because my controls were sitting inside an Edit Mode Panel.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To make this work I had to first find the Edit Mode Panel and then use the FindControl routine in its class.&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 102.2%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; height: 177px; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.empPanel = (EditModePanel)Utility.FindAndValidateControl(TemplateContainer, &lt;span style="color: #006080"&gt;"RelatedLinkDisplayPanel"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.empPanel.PreRender += &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EventHandler(RelatedLinkDisplayPanel_PreRender);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.lblTitle = (Label)Utility.FindAndValidateControl(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.empPanel, &lt;span style="color: #006080"&gt;"tbRelatedLinkTitle"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.repLinks = (Repeater)Utility.FindAndValidateControl(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.empPanel, &lt;span style="color: #006080"&gt;"repRelatedLinkItems"&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The FindAndValidateControl is a routine I wrote to do call the FindControl routine and make sure that the value passed back is not null.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 103.05%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; height: 180px; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; FindAndValidateControl(System.Web.UI.Control controlContainer, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; controlName)&lt;br /&gt;{            &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; returnValue = controlContainer.FindControl(controlName);&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (returnValue == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ConfigurationErrorsException(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #006080"&gt;"{0} not found. Corrupt control template."&lt;/span&gt;, controlName));&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; returnValue;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once I figured out that the parent container mattered I was on my way.&amp;nbsp; But it took me a few times staring at the "Control not found error" before I figured out what was going on.&amp;nbsp; Just in case you are wondering I have not done a lot of ASP.Net control development so I realize I may have made a rookie mistake.&lt;/p&gt;&lt;br /&gt;&lt;h5&gt;ItemFieldValue vs. Value&lt;/h5&gt;&lt;br /&gt;&lt;p&gt;The next problem I ran into was a difference in the way the BaseFieldControl &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.basefieldcontrol.value.aspx" target="_blank"&gt;Value&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.basefieldcontrol.itemfieldvalue.aspx" target="_blank"&gt;ItemFieldValue&lt;/a&gt; properties work.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;In my control I had put an override in for the Value property (per the Custom Control Walk-through).&amp;nbsp; This works great when you are in Edit mode (I assume it also works when in New mode).&amp;nbsp; But when in Display mode I discovered that the Value property was not being set.&amp;nbsp; The documentation clearly states that when the control is loaded the Value is supposed to be given the same value as the ItemFieldValue property.&amp;nbsp; Well this did not happen in my control.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To get around the issue I created a special handler for my Display Mode panel pre-render event.&lt;/p&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 104.02%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; height: 285px; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; RelatedLinkDisplayPanel_PreRender(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; item, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    EnsureChildControls();&lt;br /&gt;&lt;br /&gt;    RelatedLinkValue fieldValue = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RelatedLinkValue(ItemFieldValue.ToString());&lt;br /&gt;    QueryService queryService = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; QueryService();&lt;br /&gt;    DataTable queryResults = queryService.GetCategoryItems(fieldValue.Category, PropertyService.RelatedLinkPath, &lt;span style="color: #006080"&gt;"PublishingPageContent"&lt;/span&gt;);&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.lblTitle.Text = fieldValue.Title;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.repLinks.DataSource =  queryResults;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.repLinks.DataBind();&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the PreRender event I call the EnsureChildControls (for the same reason why it should be called in the Value override) and I use the ItemFieldValue property.&lt;/p&gt;&lt;br /&gt;&lt;h5&gt;Conclusion&lt;/h5&gt;&lt;br /&gt;&lt;p&gt;I was able to consolidate my Edit and Display mode rendering templates into one control without too much effort.&amp;nbsp; I did run into some gotchas, but nothing that made me think I had made a big mistake.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;nbsp; &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:338b5d2d-6496-48c3-b194-12e5eace73e2" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Rendering%20Template" rel="tag"&gt;Rendering Template&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Field%20Control" rel="tag"&gt;Field Control&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-8488002346981734109?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/eZh0BtYQtEQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/eZh0BtYQtEQ/creating-rendering-template-that.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/creating-rendering-template-that.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-6168181757172950389</guid><pubDate>Wed, 16 Apr 2008 03:45:00 +0000</pubDate><atom:updated>2008-04-15T23:45:40.973-04:00</atom:updated><title>Publishing Pages List Template ID</title><description>&lt;p&gt;The Publishing Pages List BaseTemplate ID is 850.&amp;nbsp; &lt;/p&gt; &lt;p&gt;It is not listed in the SPListTemplateType enumeration.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-6168181757172950389?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/4Uvv5QaJx3U" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/4Uvv5QaJx3U/publishing-pages-list-template-id.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/publishing-pages-list-template-id.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7072392778159644194</guid><pubDate>Mon, 14 Apr 2008 17:18:00 +0000</pubDate><atom:updated>2008-04-14T13:18:44.519-04:00</atom:updated><title>SharePoint Community Kit Wiki (or Lipstick on a Pig)</title><description>&lt;p&gt;Recently the development team at work started using a Wiki to keep track of information that is important to the team.&amp;nbsp; Since our company has standardized on using SharePoint for Collaboration solutions we used the Wiki featured delivered from Microsoft (via the &lt;a href="http://www.codeplex.com/CKS" target="_blank"&gt;Community Kit for SharePoint&lt;/a&gt;).&lt;/p&gt; &lt;p&gt;I must say I am very unimpressed by the SharePoint Wiki.&amp;nbsp; I don't want to take anything away from the community effort that developed the Wiki template for SharePoint.&amp;nbsp; I'm sure the community has done the best they can to develop a Wiki application on top of SharePoint (&lt;em&gt;although it does appear to be missing some basic functionality one would expect from a Wiki.. Categories, Page Discussions&lt;/em&gt;).&amp;nbsp; Perhaps SharePoint is not the best platform to host a Wiki.&lt;/p&gt; &lt;p&gt;Here is a short list of my main concerns with using the SharePoint Wiki.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;1. Content is stored in a single list&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;As most know SharePoint starts to perform badly whenever a list contains more than 1000 items (this number is debated, what is not debated is that SharePoint performance degrades as list size grows).&lt;/p&gt; &lt;p&gt;The Wiki appears to be storing all pages directly in the root of a Document list.&amp;nbsp; So after my Wiki has 1000 pages I will start to see a major slowdown.&amp;nbsp; I am really surprised that categories (acting as Folders) were not implemented.&amp;nbsp; To me this would have been a natural way to help reduce the impact of having a large list of Wiki pages.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;2. Poor Search &lt;/strong&gt;&lt;/p&gt; &lt;p&gt;This is my #1 complaint with our new Wiki.&amp;nbsp; In my opinion a Wiki is only as good as its search engine.&amp;nbsp; And unfortunately SharePoint search is still not as good as it can be.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;When I compare the SharePoint Wiki features and functionality to something like &lt;a href="http://www.screwturn.eu/Default.aspx?AspxAutoDetectCookieSupport=1" target="_blank"&gt;ScrewTurn&lt;/a&gt; I am left with one thought..&amp;nbsp; the SharePoint Wiki sucks.&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0df31a2e-dc6e-4d09-ae35-1947d6775f9b" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/ShrarePoint" rel="tag"&gt;ShrarePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Community%20Kit%20for%20SharePoint" rel="tag"&gt;Community Kit for SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Wiki" rel="tag"&gt;Wiki&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ScrewTurn" rel="tag"&gt;ScrewTurn&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7072392778159644194?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/TmwCf5oKzCg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/TmwCf5oKzCg/sharepoint-community-kit-wiki-or.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/sharepoint-community-kit-wiki-or.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-469105910215809321</guid><pubDate>Sun, 13 Apr 2008 18:31:00 +0000</pubDate><atom:updated>2008-04-13T14:31:17.040-04:00</atom:updated><title>FieldID class</title><description>&lt;p&gt;I came across a very useful class in the Publishing library.&lt;/p&gt; &lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 99.64%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; height: 33px; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 95.73%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; height: 16px; background-color: #f4f4f4; border-bottom-style: none"&gt;Microsoft.SharePoint.Publishing.FieldId&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The FieldId class contains a list of commonly used field ids.&amp;nbsp; I like it because it gives me an easy way to reference fields without having to worry about Internal Name vs. Display Name.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Since this is in the Publishing library you will have to have SharePoint 2007 to take advantage.&lt;/p&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b60eea09-d500-4753-87a8-9feb1dbbeadd" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Field" rel="tag"&gt;Field&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Publishing" rel="tag"&gt;Publishing&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-469105910215809321?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/6V_4vGDQw0s" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/6V_4vGDQw0s/fieldid-class.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/fieldid-class.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-1777192243814934704</guid><pubDate>Sun, 13 Apr 2008 18:30:00 +0000</pubDate><atom:updated>2008-04-13T14:30:11.095-04:00</atom:updated><title>Missing Method Exception (or why my Unit Tests would not work with my SharePoint project)</title><description>&lt;p&gt;I'm using some test driven development concepts on a little SharePoint development project.&lt;/p&gt; &lt;p&gt;I noticed that I kept running into a really strange error every time I added a new Method to my SharePoint project.&lt;/p&gt; &lt;p&gt;Whenever I would run my new Unit Test I would get a System.MissingMethodException error saying that the method in my SharePoint project could not be found.&lt;/p&gt; &lt;p&gt;Turns out that the problem was caused by the fact that the Unit Test project was loading my SharePoint assembly from the GAC.&amp;nbsp; So for me to get the tests to work I had to install the latest version of my SharePoint assembly into the GAC and then close/open Visual Studio.&lt;/p&gt; &lt;p&gt;I like to take very small steps when I develop (add some functionality, test it, add some functionality, test it).&amp;nbsp; So the idea of constantly updating the GAC and closing Visual Studio was not appealing.&lt;/p&gt; &lt;p&gt;I considered removing my SharePoint assembly from the GAC, but I put it in there for some legitimate reasons.&lt;/p&gt; &lt;p&gt;After much trial and error I found a solution that works okay (but is not ideal).&amp;nbsp; I configured my Unit Test project to install the SharePoint dll in the GAC whenever the project is compiled.&amp;nbsp; And I run the Unit Tests in Debug mode.&amp;nbsp; With this setup I am able to get instant feedback from my changes.&lt;/p&gt; &lt;p&gt;As I said it is not ideal, but works.&lt;/p&gt; &lt;p&gt;To install my SharePoint dll in the GAC I added a Post Build event to my Unit Test project.&amp;nbsp; It just runs the gacutil command.&lt;/p&gt; &lt;p&gt;To run my Unit Tests in debug mode I launch my tests using the Visual Studio Debug option rather than Run option.&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh6.ggpht.com/jeffdalton1/SAJQ_VeKvkI/AAAAAAAAABk/J4csA4cmZEQ/s1600-h/VSNET_UnitTest_SnapShot%5B8%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="232" alt="VSNET_UnitTest_SnapShot" src="http://lh6.ggpht.com/jeffdalton1/SAJRJVeKvlI/AAAAAAAAABs/vtEfLeqBIXk/VSNET_UnitTest_SnapShot_thumb%5B4%5D.jpg?imgmax=800" width="433" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;I am using Visual Studio 2008 Test project for my Unit Tests.&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:a0ed2b7d-ceea-489b-9987-3669db1f3ce7" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/TDD" rel="tag"&gt;TDD&lt;/a&gt;,&lt;a href="http://technorati.com/tags/UnitTests" rel="tag"&gt;UnitTests&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Visual%20Studio%202008" rel="tag"&gt;Visual Studio 2008&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-1777192243814934704?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/Bh9hvrpd5Ig" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/Bh9hvrpd5Ig/missing-method-exception-or-why-my-unit.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/missing-method-exception-or-why-my-unit.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-8912271615026435250</guid><pubDate>Sat, 12 Apr 2008 02:55:00 +0000</pubDate><atom:updated>2008-04-11T23:15:10.852-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Mistakes</category><category domain="http://www.blogger.com/atom/ns#">Features</category><category domain="http://www.blogger.com/atom/ns#">SharePoint</category><title>Six hours later...</title><description>I finally figured out why my Feature would not create my Site Columns and Content Types.&lt;br&gt;&lt;br&gt;I mistyped the ElementManifests statement in the Feature definition.&lt;br&gt;&lt;br&gt;Instead of using the ElementManifest tag I used the ElementFile tag. Uggg...&lt;br&gt;&lt;br&gt;&lt;feature&gt; &lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 117.35%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; height: 173px; background-color: #f4f4f4"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Feature&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://schemas.microsoft.com/sharepoint/"&lt;/span&gt; ...&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ElementManifests&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ElementManifest&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Location&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="SiteColumns.xml"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt; &lt;span style="color: #008000"&gt;&amp;lt;!-- Right --&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ElementFile&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Location&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="SiteColumns.xml"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt; &lt;span style="color: #008000"&gt;&amp;lt;!-- Wrong --&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ElementManifests&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Feature&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;elementmanifests&gt;&lt;br&gt;Rookie mistake. I didn't look closely at my Feature file because I was sure I had screwed up something in the element file that contained by Field definitions.&lt;/p&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:66eae852-0440-49e9-8216-a5621ad9945b" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Features" rel="tag"&gt;Features&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Mistakes" rel="tag"&gt;Mistakes&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-8912271615026435250?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/badNgMTc4oU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/badNgMTc4oU/six-hours-later.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/six-hours-later.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7994416804541116278</guid><pubDate>Tue, 08 Apr 2008 01:45:00 +0000</pubDate><atom:updated>2008-04-07T21:46:49.800-04:00</atom:updated><title>Load Testing SharePoint (Lessons Learned) (Part 2)</title><description>&lt;p&gt;In &lt;a href="http://sharepoint-journey.blogspot.com/2008/03/load-testing-sharepoint-lessons-learned.html" target="_blank"&gt;part 1&lt;/a&gt; I discussed the setup of my load testing environment and tests.&amp;#160; In part 2 I want to focus on the tests runs and what configuration I had to make to get them to work.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Bottlenecks oh Bottlenecks, wherefore art thou Bottlenecks&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Right out of the gate I ran into trouble.&amp;#160; My tests showed a bottleneck at 4 requests per second.&amp;#160; The CPU was running @ 25 - 35% no matter what user load VSTS used (remember I was using goal based testing that would keep loading users until the goal was met).&amp;#160; I tried several different tests and they all had the same result.&amp;#160; So I knew there was a bottleneck somewhere.&lt;/p&gt;  &lt;p&gt;I started by looking at the network.&amp;#160; Specifically I focused on the virtual's network adaptor.&amp;#160; I was worried that there was some sort of VMWare configuration problem.&amp;#160; To test the network I used a file copy test (I uploaded and downloaded a large file to the web server).&amp;#160; The test showed that the network was working just fine.&lt;/p&gt;  &lt;p&gt;Then it hit me, the web server was configured to only support Integrated Windows authentication (NTLM).&amp;#160; So I configured SharePoint (and IIS) to support Anonymous authentication.&amp;#160; Bam, the bottleneck was gone.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Size Matters&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;So I ran my first set of tests.&amp;#160; Unfortunately I noted a fairly significant difference between the out of the box Article page and our custom page.&lt;/p&gt;  &lt;p&gt;Next I used the &lt;a href="http://www.codeplex.com/sptdatapop" target="_blank"&gt;SharePoint Test Data Population Tool&lt;/a&gt; to create a site collection that contained 22,000 sites and about 50,000 pages.&lt;/p&gt;  &lt;p&gt;Then I ran the tests again with some very surprising results.&amp;#160; The out of the box Article page when from 114 requests per second to 56 requests per second.&amp;#160; That's right we recorded an almost 100% decrease in performance just due to the size of the site collection.&amp;#160; &lt;/p&gt;  &lt;p&gt;Our custom page's did not experience the same percentage of slow down (actually their performance improved, but that was due to improvements we made to the code).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Summing Up&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Performance testing SharePoint is a tedious but necessary task.&amp;#160; Here are my lessons learned from the exercise.&lt;/p&gt;  &lt;p&gt;1. Plan, Plan, Plan&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#333333" size="2"&gt;Establish the test goals&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#333333" size="2"&gt;Determine which tests you need to run&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#333333" size="2"&gt;Determine which tools you will use&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#333333" size="2"&gt;Determine the setup/configuration of your SharePoint and Load test environments.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;2. Dry run the tests (leave plenty of time to work through issues)&lt;/p&gt;  &lt;p&gt;3. Don't test with an empty site collection&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8e060d5d-3097-4a93-87b6-c9294eb9a894" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Performance" rel="tag"&gt;Performance&lt;/a&gt;,&lt;a href="http://technorati.com/tags/visual%20Studio%20Team%20System" rel="tag"&gt;visual Studio Team System&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Load%20Testing" rel="tag"&gt;Load Testing&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7994416804541116278?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/KDBWNONAV-w" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/KDBWNONAV-w/load-testing-sharepoint-lessons-learned.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/load-testing-sharepoint-lessons-learned.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-8340238457129820368</guid><pubDate>Mon, 07 Apr 2008 02:51:00 +0000</pubDate><atom:updated>2008-04-07T15:12:46.449-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">SPSiteDataQuery</category><category domain="http://www.blogger.com/atom/ns#">SharePoint</category><category domain="http://www.blogger.com/atom/ns#">CrossListQueryCache</category><category domain="http://www.blogger.com/atom/ns#">Performance</category><title>Musing on CrossListQueryCache class</title><description>&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#333333" size="2"&gt;The SharePoint CrossListQueryCache class provides a highly scalable way to run site wide queries.&amp;nbsp; It provides all the power of SPSiteDataQuery without the performance implications.&amp;nbsp; However it has some major gotchas that you should be aware of before using.&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I'm always looking for ways to improve application performance (and with SharePoint I have more opportunities than time). I was focused on some code we use to pull list items.&amp;nbsp; This code is in the critical path for our runtime performance and scalability.&amp;nbsp; It is the perfect place for cached data query.&amp;nbsp; So I started looking at different ways to do data querying in SharePoint.&amp;nbsp; &lt;/p&gt; &lt;p&gt;My first stop was on Google where I found some information about the SharePoint SPSiteDataQuery object. &lt;a href="http://sharingpoint.blogspot.com/2006/10/spsitedataquery-vs-getlistitems.html" target="_blank"&gt;According to Eric Shupps (The SharePoint Cowboy :D) SPSiteDataQuery is great for small data sets and small to medium traffic environments&lt;/a&gt;. Eric actually recommends using the good ole GetListItems method.&amp;nbsp; Well we are using GetListItems today, so I was not encouraged.&amp;nbsp; &lt;a href="http://blog.mastykarz.nl/2008/03/21/content-query-web-part-vs-custom-aggregation-web-part/" target="_blank"&gt;Waldek Mastykarz put together a really nice posting that compares several different approaches for querying lists (just what I needed)&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Even though I had read the warnings about SPSiteDataQuery I decided to check it out (for some reason I really like to repeat the mistakes of others ;-).&amp;nbsp; I really like the functionality provided by the class. I used &lt;a href="http://www.aisto.com/roeder/dotnet/" target="_blank"&gt;Reflector&lt;/a&gt; to look under the covers.&amp;nbsp; I didn't seen anything crazy going on (makes a call to COM method called CrossListQuery... I didn't bother chasing it to the SQL layer).&amp;nbsp; I ran some performance tests with it, but didn't see a compelling reason to dump GetListItems for this routine.&lt;/p&gt; &lt;p&gt;Next I jumped into the CrossListQueryInfo/CrossListQueryCache routines. It is worth mentioning that these are in the Microsoft.SharePoint.Publishing library which means you have to have SharePoint 2007 (WSS v3 does not include this library). What I found shocked and delighted me (hmm, doesn't sound quite right).&lt;/p&gt; &lt;p&gt;&lt;strong&gt;First the shock...&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;According to the documentation CrossListQueryCache was built specifically for what I needed to do. Query one or more lists and store the results in cache so subsequent calls are at near lightening speed. &lt;/p&gt; &lt;p&gt;But when I ran my tests I was seeing no better performance than SPSiteDataQuery (all you haters saying CrossListQueryInfo.UseCache must be set to true, bite your tongue and keep reading). I assumed I was doing something wrong, so I cracked open the worlds best documents (the source code).&lt;/p&gt; &lt;p&gt;I used Reflector (one of the best dam tools ever developed) to look at the routine I was using, CrossListQueryCache.GetSiteData(SPWeb).&amp;nbsp; Well according to the code there is no caching going on, infact this routine is nothing more than a wrapper for SPSiteDataQuery.&amp;nbsp; So a little more checking and I discovered that something strange was afoot in the CrossListQueryCache library.&amp;nbsp; &lt;/p&gt; &lt;p&gt;There are 4 overloads for CrossListQueryCache.GetSiteData.&amp;nbsp; Two of the overloads cache the results and two do not.&lt;/p&gt; &lt;table cellspacing="0" cellpadding="2" width="431" border="0"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="280"&gt;&lt;strong&gt;CrossListQueryCache Routine&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="148"&gt;&lt;strong&gt;Uses Cache&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="280"&gt;GetSiteData (SPSite)&lt;/td&gt; &lt;td valign="top" width="148"&gt;Yes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="280"&gt;GetSiteData (SPWeb)&lt;/td&gt; &lt;td valign="top" width="148"&gt;No&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="280"&gt;GetSiteData (SPSite, String)&lt;/td&gt; &lt;td valign="top" width="148"&gt;Yes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="280"&gt;GetSiteData (SPWeb, SPSiteDataQuery)&lt;/td&gt; &lt;td valign="top" width="148"&gt;No&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;So unless you are using one of the overloads that supports caching (and have the CrossListQueryInfo.UseCache property set to true) you might as well use SPSiteDataQuery.&amp;nbsp; &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#333333" size="2"&gt;There is one other gotcha with the overloads that support cache.&amp;nbsp; Your query cannot contain "&amp;lt;UserId/&amp;gt;" tag.&amp;nbsp; If it does then cache is not used.&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;Next the delight...&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;When you use the GetSiteData routines that support caching you see major performance improvements.&amp;nbsp; In fact my testing showed that the performance of CrossListQueryCache was as good as the Content By Query Control (not surprising since they are both caching their results).&lt;/p&gt; &lt;p&gt; &lt;div style="padding-right: 0px; padding-left: 0px; background: #808080; padding-bottom: 0px; margin-left: 4px; margin-right: 4px; padding-top: 0px"&gt; &lt;div style="border-right: #2e595c 1px solid; border-top: #2e595c 1px solid; background: #fff; left: -2px; border-left: #2e595c 1px solid; color: black; border-bottom: #2e595c 1px solid; position: relative; top: -2px"&gt; &lt;div style="border-right: blue 1px solid; border-top: blue 1px solid; background: #3f73b6; border-left: blue 1px solid; width: 100%; color: white; border-bottom: blue 1px solid"&gt;&lt;span style="width: 100%"&gt;Code Snippet&lt;/span&gt;&lt;/div&gt;&lt;pre&gt;CrossListQueryInfo clqi = &lt;/span&gt;&lt;span style="color: #a31515"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt; CrossListQueryInfo();&lt;br /&gt;clqi.Query = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;OrderBy&amp;gt;&amp;lt;FieldRef Ascending=\"FALSE\" Name=\"Title\" /&amp;gt;&amp;lt;/OrderBy&amp;gt;&amp;lt;Where&amp;gt;&amp;lt;BeginsWith&amp;gt;&amp;lt;FieldRef Name=\"Title\" /&amp;gt;&amp;lt;Value Type=\"Text\"&amp;gt;Test&amp;lt;/Value&amp;gt;&amp;lt;/BeginsWith&amp;gt;&amp;lt;/Where&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.ViewFields = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;FieldRef Name=\"Title\" /&amp;gt;&amp;lt;FieldRef Name=\"ContentType\" /&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.Lists = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;Lists BaseType=\"1\" /&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.Webs = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;Webs Scope=\"SiteCollection\" /&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.UseCache = &lt;/span&gt;&lt;span style="color: #a31515"&gt;true&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;&lt;br /&gt;CrossListQueryCache clqc = &lt;/span&gt;&lt;span style="color: #a31515"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt; CrossListQueryCache(clqi);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #ff00ff"&gt;DataTable&lt;/span&gt;&lt;span style="color: #000000"&gt; tbl = clqc.GetSiteData(SPContext.Current.Web);&lt;br /&gt;&lt;/PRE&lt; DIV&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The code above (which does not use caching since it passes in the Web) averaged 0.0500 seconds.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;That same code slightly modified (see below) averaged 0.0008 seconds.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;div style="padding-right: 0px; padding-left: 0px; background: #808080; padding-bottom: 0px; margin-left: 4px; margin-right: 4px; padding-top: 0px"&gt;&lt;br /&gt;&lt;div style="border-right: #2e595c 1px solid; border-top: #2e595c 1px solid; background: #fff; left: -2px; border-left: #2e595c 1px solid; color: black; border-bottom: #2e595c 1px solid; position: relative; top: -2px"&gt;&lt;br /&gt;&lt;div style="border-right: blue 1px solid; border-top: blue 1px solid; background: #3f73b6; border-left: blue 1px solid; width: 100%; color: white; border-bottom: blue 1px solid"&gt;&lt;span style="width: 100%"&gt;Code Snippet&lt;/span&gt;&lt;/div&gt;&lt;pre&gt;CrossListQueryInfo clqi = &lt;/span&gt;&lt;span style="color: #a31515"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt; CrossListQueryInfo();&lt;br /&gt;clqi.Query = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;OrderBy&amp;gt;&amp;lt;FieldRef Ascending=\"FALSE\" Name=\"Title\" /&amp;gt;&amp;lt;/OrderBy&amp;gt;&amp;lt;Where&amp;gt;&amp;lt;BeginsWith&amp;gt;&amp;lt;FieldRef Name=\"Title\" /&amp;gt;&amp;lt;Value Type=\"Text\"&amp;gt;Test&amp;lt;/Value&amp;gt;&amp;lt;/BeginsWith&amp;gt;&amp;lt;/Where&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.ViewFields = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;FieldRef Name=\"Title\" /&amp;gt;&amp;lt;FieldRef Name=\"ContentType\" /&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.Lists = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;Lists BaseType=\"1\" /&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.Webs = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;"&amp;lt;Webs Scope=\"SiteCollection\" /&amp;gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;clqi.UseCache = &lt;/span&gt;&lt;span style="color: #a31515"&gt;true&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;&lt;br /&gt;CrossListQueryCache clqc = &lt;/span&gt;&lt;span style="color: #a31515"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt; CrossListQueryCache(clqi);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #ff00ff"&gt;DataTable&lt;/span&gt;&lt;span style="color: #000000"&gt; tbl = clqc.GetSiteData(SPContext.Current.Site, CrossListQueryCache.ContextUrl());&lt;br /&gt;&lt;/PRE&lt; DIV&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Slightly Different Results&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As I said the performance is great, but one thing really bothered me. The DataTable results did not match.&amp;nbsp; Everything about the code is identical (same query, same CrossListQueryInfo configuration), but different results.&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;I discovered that the routines that actually use cache contain some extra code that does a check to see if the item is checked-in.&amp;nbsp; If it is then it shows it, if not then it does not.&amp;nbsp; While the code that does not use cache returns all items that match the query (even those that are not checked-in).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I was worried that the routines were not using the same technique to query across the site lists, so I did some digging with Reflector.&amp;nbsp; What I found is that they both use the SPWeb.GetSiteData to execute the query.&amp;nbsp; The routines that cache the results do a little extra work to trim the results.&amp;nbsp; Just take a look at CachedArea.GetCrossListQuery if you want to see what is happening.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Anyway the end result was that I found that if used correctly the CrossListQueryCache object operates with the same efficiency of the Content Query Control. It provides an out of the box way to have your GetSiteData results cached. I highly recommended it if you are using SharePoint 2007 and not WSS 3.&lt;/p&gt;&lt;br /&gt;&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b27ae3bc-c85b-4b51-a225-4a7bef834852" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/SharePoint" rel="tag"&gt;SharePoint&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Performance" rel="tag"&gt;Performance&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Development" rel="tag"&gt;Development&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-8340238457129820368?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/5dak6SJS_j0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/5dak6SJS_j0/musing-on-crosslistquerycache-class.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/04/musing-on-crosslistquerycache-class.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-1506206266852737637</guid><pubDate>Sun, 16 Mar 2008 18:26:00 +0000</pubDate><atom:updated>2008-03-23T16:10:16.381-04:00</atom:updated><title>Load Testing SharePoint (Lessons Learned) (Part 1)</title><description>&lt;p&gt;I want to share some experiences from a recent load testing exercise I performed with SharePoint. &lt;/p&gt;  &lt;p&gt;I am working on a web content management project that requires A LOT of customizations to SharePoint. The team needed to understand how these customizations would perform and scale. So I dusted off my limited knowledge of load testing with Visual Studio Team Test and went to work. &lt;/p&gt;  &lt;p&gt;First I established my testing environment. I started by setting up my test agent. I was able to commandeer an old R&amp;amp;D server (HP 385, Dual Pentium III, 2 GB RAM, 1 GB NIC) for my cause. I wasn't sure, but suspected that this would be more than enough machine for my needs (oh yeah, its business time). Setup was a breeze, I just installed Visual Studio Team Test 2008 and my load agent was ready. &lt;/p&gt;  &lt;p&gt;Next I needed to prepare my SharePoint environment. I already had a virtualized (is that a word) environment for SharePoint. Actually I had two to choose from, one dedicated to integration testing for the development team and another for user acceptance testing. I decided to go with the integration test environment because it was located inside of the corporate network (no messy firewalls).&lt;/p&gt;  &lt;p&gt;Next I needed to create my web tests. This step required me to put on a thinking cap. There are many different approaches for load testing and I am not going to discuss them in this article. I chose to create tests that would isolate specific pieces of functionality (rather than trying to mimic usage patterns).&amp;#160; By using this approach I could clearly understand how our customizations would compare to out of the box SharePoint.&lt;/p&gt;  &lt;p&gt;Here is a list of my tests&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="460" border="1"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="33"&gt;&lt;strong&gt;ID&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="234"&gt;&lt;strong&gt;Test&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="191"&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="38"&gt;1&lt;/td&gt;        &lt;td valign="top" width="231"&gt;HTML page with Hello World text&lt;/td&gt;        &lt;td valign="top" width="190"&gt;This is not a SharePoint item.&amp;#160; I created it so I could have an overall for the test environment.          &lt;br /&gt;          &lt;br /&gt;The results from this test represent the fastest the server can go.&amp;#160; This will act as a high water mark for me to compare my results to.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="42"&gt;2&lt;/td&gt;        &lt;td valign="top" width="229"&gt;SharePoint Publishing Article Page&lt;/td&gt;        &lt;td valign="top" width="189"&gt;This is an out of the box SharePoint item.          &lt;br /&gt;          &lt;br /&gt;The results from this test represent a baseline for me to compare my test results against.&amp;#160; My tests results should be in the same neighborhood as these test results.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="45"&gt;3&lt;/td&gt;        &lt;td valign="top" width="228"&gt;Our Customized SharePoint Page Layout with one customized control.&lt;/td&gt;        &lt;td valign="top" width="188"&gt;This represents a very lightweight version of our customizations.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="47"&gt;4&lt;/td&gt;        &lt;td valign="top" width="227"&gt;Our Customized SharePoint Page Layout with two customized controls.&lt;/td&gt;        &lt;td valign="top" width="190"&gt;The idea is to add a small piece of functionality so I can understand how the change impacts the test results.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;I ran each one of those tests independently.&amp;#160; The idea was to take a single test and stress the system.&lt;/p&gt;  &lt;p&gt;I used goal based load tests in VSTT (a new feature for VS.Net 2008).&amp;#160; My goal was to stress the Web Server so the CPU would run between 70 - 90%.&amp;#160; Goal based testing is why I decided to avoid the firewalls (Goal based testing requires that the load agent communicate with the performance counters on the target machines).&amp;#160; &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#333333" size="2"&gt;VSTT will continue to load transactions until the goal is reached.&amp;#160; If the goal is never reached then VSTT will load to the maximum number of requests/users specified in the load test.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font color="#333333" size="2"&gt;Now I had everything ready to go... or so I thought.&amp;#160; In Part 2 I will go into detail about tweaks I had to make to my SharePoint environment so I could get the load tests to work correctly.&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-1506206266852737637?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/hTrJkdtBong" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/hTrJkdtBong/load-testing-sharepoint-lessons-learned.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/03/load-testing-sharepoint-lessons-learned.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-2468215977738386917</guid><pubDate>Sat, 08 Mar 2008 19:41:00 +0000</pubDate><atom:updated>2008-03-15T16:58:30.343-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Tools</category><category domain="http://www.blogger.com/atom/ns#">Test</category><title>SPTD (no its not a venereal disease, but can cause hives)</title><description>Test Data Load Tool is a nifty little utility for creating data in your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;WSS&lt;/span&gt; or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;SharePoint&lt;/span&gt; site. You can download the tool at &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;CodePlex&lt;/span&gt; &lt;a href="http://www.codeplex.com/sptdatapop"&gt;http://www.codeplex.com/sptdatapop&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The tool provides a repeatable way to create test data for your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;SharePoint&lt;/span&gt; sites. It is extremely cool and even with the warts it is worth the time to sit and learn it. If you are a tester for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;SharePoint&lt;/span&gt; solutions you need to add this one to your bag of tricks. If you are a developer you will &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;appreciate&lt;/span&gt; the base framework and potential.&lt;/p&gt;&lt;p&gt;The tool comes in two flavors (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;WSSDW&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;exe&lt;/span&gt;) and (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;MOSSDW&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;exe&lt;/span&gt;). They are in &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_11"&gt;separate&lt;/span&gt; download packages so if you want to load data for things like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;SSO&lt;/span&gt;, publishing portals, &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_13"&gt;audiences&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;SharePoint&lt;/span&gt; features) you will need to get both downloads. The tools are fairly easy to grasp, just take some time and go through the help files and samples.&lt;br /&gt;&lt;br /&gt;That said the tools are buggy. Here are some things I learned the hard way.&lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The Delete option works about half the time... I finally quite using it and went another route. I'm sure the code is working as intended, but when you say delete you expect everything to go. Perhaps a -force option is needed with the delete.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;ModifyExisting&lt;/span&gt; depends on "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;ModifyOne&lt;/span&gt;" interface being implemented, if the interface is not implemented no updates are made. It is extremely frustrating when you want to do something simple (ex. change the title of a web) and discover that the Webs class does not do anything in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;ModifyOne&lt;/span&gt;. &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Pages have to be checked out to modify them (this may make you go &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_18"&gt;Duh&lt;/span&gt;, but I was hoping to not have to worry about things like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;checkin&lt;/span&gt;/checkout/publish since it is a test tool). I ended up having 3 statements per page (one with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;OpenorCreate&lt;/span&gt;, one with checkout, one with publish). &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Don't expect your script to work the first (or second, or third) time. Plan on having plenty of time to work through issues as you learn about the subtle &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_21"&gt;nuances&lt;/span&gt; of the tool. It took me a good 2 days to get the kinks worked out of my script, but once I had it done I could bounce from environment to &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_22"&gt;environment&lt;/span&gt; and setup a site that was test worthy (&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_23"&gt;Seinfeld&lt;/span&gt; reference).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Depending on the amount / type of work your script needs to do it can take a while to run the script. I uploaded about 200 images and documents. The first run took about 30 minutes to do the upload, but every run after that was &lt; 1 minute.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-2468215977738386917?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/tpgj6PRix1o" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/tpgj6PRix1o/sptd-no-its-not-venereal-disease-but.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/03/sptd-no-its-not-venereal-disease-but.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-7860665148606950098</guid><pubDate>Sat, 08 Mar 2008 01:49:00 +0000</pubDate><atom:updated>2008-03-08T10:04:30.304-05:00</atom:updated><title>Zune Wiener</title><description>&lt;a href="http://3.bp.blogspot.com/_WsP10mKL7i0/R9KqvwQrY6I/AAAAAAAAAAM/y0qcGhAKlKA/s1600-h/IMG00056.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5175386659187549090" style="FLOAT: right; MARGIN: 0px 0px 10px 10px; CURSOR: hand" alt="" src="http://3.bp.blogspot.com/_WsP10mKL7i0/R9KqvwQrY6I/AAAAAAAAAAM/y0qcGhAKlKA/s320/IMG00056.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;I was one of the lucky Zune winners at SPC2008. Yeah! I never win jack so I'm in shock.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-7860665148606950098?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/F-GELScTrlI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/F-GELScTrlI/zune-wiener.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_WsP10mKL7i0/R9KqvwQrY6I/AAAAAAAAAAM/y0qcGhAKlKA/s72-c/IMG00056.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/03/zune-wiener.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8096263481091318859.post-2696278205874111479</guid><pubDate>Fri, 07 Mar 2008 01:07:00 +0000</pubDate><atom:updated>2008-03-06T20:15:01.702-05:00</atom:updated><title>SPC 2008 Day 4</title><description>This was the final day of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SPC&lt;/span&gt; 2008.  It was a great conference and I'm really glad I came. &lt;br /&gt;&lt;br /&gt;The day started with a session from Russ White in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;PSS&lt;/span&gt;.  He was talking about how &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;MSFT&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;PSS&lt;/span&gt; troubleshoots &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;SharePoint&lt;/span&gt; problems.  The title was a little misleading since Russ spent about half of the talk providing best practices for capturing information about the problem (nothing to do with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;SharePoint&lt;/span&gt;).  The actual &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;SharePoint&lt;/span&gt; data was a little lite.  Would have been nice to focus on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;SharePoint&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Next I went to Tyler Butlers presentation on deploying solutions and content throughout the farm.  Tyler gave some solid &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_8"&gt;practical&lt;/span&gt; advice for the content deployment tools.  He also showed some information about known problems with the tools.  He mentioned that in the next 90 days an update that addresses several more fixes should be coming out.&lt;br /&gt;&lt;br /&gt;The final session was presented by Andy Hopkins and Paul Learning.  They talked about their findings from creating a highly scalable &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;SharePoint&lt;/span&gt; solution.  The information they shared was priceless.  I'm so happy that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;MSFT&lt;/span&gt; made the investment to really find out what &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;SharePoint&lt;/span&gt; can do.  This made me feel much better about what we are doing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8096263481091318859-2696278205874111479?l=sharepoint.nailhead.net'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AdventuresInMossLand/~4/X4FN8lwGHr0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/AdventuresInMossLand/~3/X4FN8lwGHr0/spc-2008-day-4.html</link><author>jefferydalton@hotmail.com (Jeff Dalton)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sharepoint.nailhead.net/2008/03/spc-2008-day-4.html</feedburner:origLink></item></channel></rss>
